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

时间:2013-05-07 00:55:18

标签: 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());
    }
}

结果是:

Mon Jan 01 00:00:00 KST 1900
Mon Jan 01 23:30:00 KST 1900 // Where is 30 minutes here?

最有趣和最重要的线索是,这个问题只发生在1900年。

3 个答案:

答案 0 :(得分:3)

处理日期的这种不正常现象很常见。参见例如Jon Skeet's most famous answer.我正在寻找这些毛刺的实际数据库;会在找到后更新答案。

这个答案相当不完整,但可能足以让你解开;我会离开它,但鼓励你接受一个更完整的,如果发布。

答案 1 :(得分:3)

这是因为历史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

因为(根据Java)时钟在1900年1月1日0:20:08在EET转发。 TimeZone有方法确定特定日期的偏移量,TimeZone.getOffset(长日期)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()));

输出

1900-01-01 00:00:00
1900-01-02 00:00:00

答案 2 :(得分:0)

    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());
        System.out.println(cal.getTimeInMillis());
        System.out.println(DAY_MILLIS);
        System.out.println(cal.getTimeInMillis() + DAY_MILLIS);
        cal.setTimeInMillis(cal.getTimeInMillis() + DAY_MILLIS);
        System.out.println(cal.getTime());
    }
  

Mon Jan 01 00:00:00 CST 1900

     

-2209017599564

     

86400000

     

-2208931199564

     

Tue Jan 02 00:05:52 CST 1900

似乎.getTimeInMillis()返回的值与您的预期值不同。

  

getTimeInMillis

     

public long getTimeInMillis()

     

以毫秒为单位返回此Calendar的时间值。

     

返回:从纪元开始的UTC毫秒的当前时间。