从GregorianCalendar中减去一天时,小时数已损坏

时间:2009-10-18 21:41:03

标签: java datetime

我使用以下代码:

Calendar calendar = new GregorianCalendar(0,0,0);
calendar.set(Calendar.YEAR, 1942);
calendar.set(Calendar.MONTH, 3);
calendar.set(Calendar.DAY_OF_MONTH, 4);

Date date1 = calendar.getTime();

calendar.add(Calendar.DAY_OF_MONTH, -1);

Date date2 = calendar.getTime();

System.out.println(date1 + "\n" + date2);

此代码输出如下:

Sat Apr 04 00:00:00 EEST 1942
Fri Apr 03 01:00:00 EEST 1942

实际上我减去1天,时间应该保留。 但是为什么第二行输出包含1小时的时间应该是0?

修改

目前我正在欧洲/赫尔辛基时区测试我的代码。

5 个答案:

答案 0 :(得分:18)

我想你正在使用芬兰时区。在芬兰,1942年通过调整时钟从4月2日23:59:59到4月3日1:00:00引入了夏令时。 4月3日0:00:00到0:59:59的时间跨度不存在,因此Java Calendar会尽力而为。

答案 1 :(得分:1)

您使用的是最新的java版本吗?检查一下,因为在我的java安装(1.6.0_16)上它工作正常,输出是:

Sat Apr 04 00:00:00 GMT 1942
Fri Apr 03 00:00:00 GMT 1942

Sun通常会更新java-updates上的时区数据库,所以请检查您使用的是最新版本!

或者,其他事情:

也许它与夏令时有关?美国政府在第二次世界大战期间引入了夏令时,这可能是你时区的原因而不是我的原因?

答案 2 :(得分:1)

看起来图书馆正在猜测“夏令时”

可能很难为您正在做的事情定义“正确答案”。 东欧夏令时在1942年并不存在。即使在美国那里可能已经编写了图书馆代码,那年也没有DST,因为1942年的“战争时间法案”使整年时间变换了。 / p>

关于Java日期和时间问题的通常答案是使用Joda Time.我不确定这会有所帮助,但可能会有所帮助。

我的猜测是,该计划正在不正确地应用DST转换,或者只是对它可能是什么进行了最好的猜测,如果EEST在1942年存在。

答案 3 :(得分:0)

您获得的结果很可能取决于您运行代码的时区。在您当地的时区,1天的间隔可能会跨越夏令时的变化,或者您所在国家/地区的其他一次性时钟调整。

答案 4 :(得分:0)

我会给serdev的评论写另一个答案,因为单独在评论中包含很多信息有点困难。

你说你必须迭代日期并找到距离,如果你做了一些假设,这些假设必须对你的语言环境或时区有效,这并不太难。如果你忽略时间并使用你的代码从“1942年4月4日星期六”中减去一天,你就会得到“F42 Apr Apr 1942”。如果您需要查找日期之间的天数,我会自己计算:

// set two Calendars to April 1st, 1942 and April 5th, 1942 (both 0:00)
Calendar cal1 = new GregorianCalendar(1942, 3, 1);
Calendar cal2 = new GregorianCalendar(1942, 3, 5);

// divide the difference in ms by the number of ms in 24 hours and round the result
long diff = Math.round((cal2.getTimeInMillis() - cal1.getTimeInMillis()) / (24.*60*60*1000));

只需将芬兰时区划分为3.958天,但四舍五入会给出正确的4天结果。

为此,您必须假设日期是连续的,并且您的时区在开始日期和结束日期之间的变化不会超过11小时。这并非总是如此,因为在国际日期线上有一些国家的情况是“转换方向”。最近的一个案例是基里巴斯部分地区于1994年12月31日跳过,将整个国家置于日期线的一边。在改变之前,国家的时区只有几个小时,但因为它被日期划分,所以该国实际上有两个不同的日期。