仅在1900年Java日期计算中出现30分钟错误

jee*_*yul 9 java time calendar

package check;

import java.util.Calendar;

public class Test {
    public static void main(String[] args) {
        // length of a day
        long DAY_MILLIS = 1000 * 60 * 60 * 24;

        Calendar cal = Calendar.getInstance();

        cal.set(1900, 0, 1, 0, 0, 0);
        System.out.println(cal.getTime());

        cal.setTimeInMillis(cal.getTimeInMillis() + DAY_MILLIS);
        System.out.println(cal.getTime());
    }
}
Run Code Online (Sandbox Code Playgroud)

它的结果是:

Mon Jan 01 00:00:00 KST 1900
Mon Jan 01 23:30:00 KST 1900 // Where is 30 minutes here?
Run Code Online (Sandbox Code Playgroud)

最有趣和最重要的线索是这个问题发生在年仅1900年.

Evg*_*eev 5

这是因为历史 GMT 偏移量发生了变化。请参阅此处的示例http://www.timeanddate.com/worldclock/timezone.html?n=101&syear=1900。这些变化对于不同的时区是不同的。例如,在我的时区(EET),您的测试结果是不同的:

Mon Jan 01 00:00:00 EET 1900
Mon Jan 01 23:39:52 EET 1900
Run Code Online (Sandbox Code Playgroud)

因为(根据 Java)时钟在 EET 的 1900 年 1 月 1 日向前调了 0:20:08 小时。TimeZone 有方法确定特定日期的偏移量,TimeZone.getOffset(long date) API

如果底层 TimeZone 实现子类支持历史夏令时计划和 GMT 偏移更改,则此方法返回历史正确的偏移值。

请注意,如果将日历设置为 GMT 并以 GMT 打印结果,则不会出现错误。

    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    df.setTimeZone(TimeZone.getTimeZone("GMT"));
    Calendar cal = Calendar.getInstance();
    cal.setTimeZone(TimeZone.getTimeZone("GMT"));
    cal.set(1900, 0, 1, 0, 0, 0);
    System.out.println(df.format(cal.getTime()));
    cal.setTimeInMillis(cal.getTimeInMillis() + 1000 * 60 * 60 * 24);
    System.out.println(df.format(cal.getTime()));
Run Code Online (Sandbox Code Playgroud)

输出

1900-01-01 00:00:00
1900-01-02 00:00:00
Run Code Online (Sandbox Code Playgroud)