1976年3月28日到3月29日期间发生了什么与java.util.GregorianCalendar?

时间:2012-05-22 08:33:46

标签: java scala date long-integer gregorian-calendar

尝试使用GregorianCalendar,我在计算特定日期以来的天数时遇到了奇点。 在scala解释器中,我输入了:

scala>import java.util.GregorianCalendar
scala>import java.util.Calendar
scala>val dateToday = new GregorianCalendar(2012,Calendar.MAY,22).getTimeInMillis()
dateToday: Long = 1337637600000
scala>val days1 = (dateToday - (new GregorianCalendar(1976,Calendar.MARCH,28).getTimeInMillis())) / (1000*3600*24)
days1: Long = 13203
scala>val days2 = (dateToday - (new GregorianCalendar(1976,Calendar.MARCH,29).getTimeInMillis())) / (1000*3600*24)
days2: Long = 13203

我不知道1976年是闰年的事实是否重要,但是第1天和第2天本应该相隔1.这是自1970年以来唯一一次出现这种奇点的时刻。

想知道发生了什么,我计算了之前提到的两个日期之间的差异,它给我的时间差别只有23个小时!那天发生了什么?维基百科显然没有提及它。

更重要的是,如何计算自特定日期以来的实际天数?

3 个答案:

答案 0 :(得分:46)

问题

夏令时只有23个小时。

根据this 1976年3月28日至少是巴黎的夏令时。那天凌晨1点到凌晨2点之间的时间根本不存在。

虽然它必须是一个Locale问题,因为在我的计算机上我做对了:

scala> val days1 = (dateToday - (new GregorianCalendar(1976, Calendar.MARCH, 28).getTimeInMillis())) / (1000 * 3600 * 24)
days1: Long = 13203

scala> val days2 = (dateToday - (new GregorianCalendar(1976, Calendar.MARCH, 29).getTimeInMillis())) / (1000 * 3600 * 24)
days2: Long = 13202

我不在巴黎或那个当天有时间变化的地方;时间在1976年4月25日我改变了。所以我在那个日期得到了“跳过的一天”行为:

scala> val days3 = (dateToday - (new GregorianCalendar(1976, Calendar.APRIL, 25).getTimeInMillis())) / (1000 * 3600 * 24)
days3: Long = 13175

scala> val days4 = (dateToday - (new GregorianCalendar(1976, Calendar.APRIL, 26).getTimeInMillis())) / (1000 * 3600 * 24)
days4: Long = 13175
Erwin在评论中指出,你唯一注意到这里错误的日期差异的可能原因是,所有其他夏令时日都被25小时的天数所抵消,这些天也发生在那些年,当夏令时纠正了。

解决方案

使用更好的库进行日期处理。 joda-time库正确地完成了它(以及整体上更好的日期/时间框架):

import org.joda.time.Days
import org.joda.time.DateTimeConstants
import org.joda.time.DateMidnight

val d1 = new DateMidnight(1976, DateTimeConstants.APRIL, 25)
val d2 = new DateMidnight(1976, DateTimeConstants.APRIL, 26)
val x = Days.daysBetween(d1, d2).getDays()
println(x) // 1

答案 1 :(得分:4)

如果浮动除法的选项不可用,我能想到的最佳答案是在计算两天之间的差异时增加一小时(1000 * 3600):

scala> (dateToday - (new GregorianCalendar(1976, Calendar.MARCH, 28).getTimeInMillis()) + 1000*3600) / (1000 * 3600 * 24)
days1: Long = 13204
scala> (dateToday - (new GregorianCalendar(1976, Calendar.MARCH, 29).getTimeInMillis()) + 1000*3600) / (1000 * 3600 * 24)
days1: Long = 13203

它应该适用于每个日期,因为你不再受到闰时的影响。

答案 2 :(得分:3)

dhg指出我的想法:这一天是“夏令时”的一天。 由于这一天只有23小时,因此每天的欧几里德分数等于0。

事实上,使用GregorianCalendar对象仅使用日期作为毫秒,因此将一天除以整数只会截断结果。

取代欧几里德(整数)除法,尝试进行浮点除法,然后对结果进行舍入。