TimeUnit class 坏了吗?
Is the TimeUnit class broken?
我注意到 TimeUnit class 的一个奇怪行为,所以我创建了这个最小的示例来重现它。
long differenceInDays;
Calendar c1 = Calendar.getInstance();
Calendar c2 = Calendar.getInstance();
c1.setTimeInMillis(1466062306000l); // Thu Jun 16 2016 09:31:46 GMT+0200
c2.setTimeInMillis(1466028000000l); // Thu Jun 16 2016 00:00:00 GMT+0200
differenceInDays = TimeUnit.DAYS.convert(c2.getTimeInMillis() - c1.getTimeInMillis(), TimeUnit.MILLISECONDS);
System.out.println(differenceInDays); // obviously zero
c2.add(Calendar.DATE, +1);
differenceInDays = TimeUnit.DAYS.convert(c2.getTimeInMillis() - c1.getTimeInMillis(), TimeUnit.MILLISECONDS);
System.out.println(differenceInDays); // why zero and not one?
c2.add(Calendar.DATE, +1);
differenceInDays = TimeUnit.DAYS.convert(c2.getTimeInMillis() - c1.getTimeInMillis(), TimeUnit.MILLISECONDS);
System.out.println(differenceInDays); // suddenly a 1, but not a 2 like expected
很明显,第一次计算差值是0,因为日期之间没有一整天。
可是第二次加了一整天,怎么差还是0?
输出:
0
0
1
我认为这个问题与夏令时或闰年无关,因为我只计算同年,甚至同月。
Here 是一个日期毫秒计算器供您查看。
您可以通过简单的数学运算更好地了解这里发生的事情:
c1 = 1466062306000
c2 = 1466028000000
d = 86400000 // one day
c2 - c1 = -34306000 // negative, but less than one day in magnitude
c2 - c1 + d = 52094000 // less than one day
c2 - c1 + d + d = 138494000 // more than one day, less than two days
假设您使用的是 Java 8,正确的 处理方法如下:
// Decide what time zone you want to work in
ZoneId tz = ZoneId.of("Europe/Berlin");
// If you wanted the local time zone of the system,
// Use this instead:
// ZoneId tz = ZoneId.systemDefault();
// Get instants from the timestamps
Instant i1 = Instant.ofEpochMilli(1466062306000l);
Instant i2 = Instant.ofEpochMilli(1466028000000l);
// Get the calendar date in the specified time zone for each value
LocalDate d1 = i1.atZone(tz).toLocalDate();
LocalDate d2 = i2.atZone(tz).toLocalDate();
// Get the difference in days
long daysBetween = ChronoUnit.DAYS.between(d2, d1);
如果您的输入确实是 Calendar
对象而不是时间戳,我建议 Calendar.toInstant()
如 Legacy Date-Time Code 指南中所述。
如果您使用的是 Java 7 或更早版本,您会在 Joda Time 库中找到类似的功能。
如果您真的不想使用其中的任何一个,并且仍然以旧的(困难的)方式做事,那么请参阅 this example。
我注意到 TimeUnit class 的一个奇怪行为,所以我创建了这个最小的示例来重现它。
long differenceInDays;
Calendar c1 = Calendar.getInstance();
Calendar c2 = Calendar.getInstance();
c1.setTimeInMillis(1466062306000l); // Thu Jun 16 2016 09:31:46 GMT+0200
c2.setTimeInMillis(1466028000000l); // Thu Jun 16 2016 00:00:00 GMT+0200
differenceInDays = TimeUnit.DAYS.convert(c2.getTimeInMillis() - c1.getTimeInMillis(), TimeUnit.MILLISECONDS);
System.out.println(differenceInDays); // obviously zero
c2.add(Calendar.DATE, +1);
differenceInDays = TimeUnit.DAYS.convert(c2.getTimeInMillis() - c1.getTimeInMillis(), TimeUnit.MILLISECONDS);
System.out.println(differenceInDays); // why zero and not one?
c2.add(Calendar.DATE, +1);
differenceInDays = TimeUnit.DAYS.convert(c2.getTimeInMillis() - c1.getTimeInMillis(), TimeUnit.MILLISECONDS);
System.out.println(differenceInDays); // suddenly a 1, but not a 2 like expected
很明显,第一次计算差值是0,因为日期之间没有一整天。
可是第二次加了一整天,怎么差还是0?
输出:
0
0
1
我认为这个问题与夏令时或闰年无关,因为我只计算同年,甚至同月。
Here 是一个日期毫秒计算器供您查看。
您可以通过简单的数学运算更好地了解这里发生的事情:
c1 = 1466062306000
c2 = 1466028000000
d = 86400000 // one day
c2 - c1 = -34306000 // negative, but less than one day in magnitude
c2 - c1 + d = 52094000 // less than one day
c2 - c1 + d + d = 138494000 // more than one day, less than two days
假设您使用的是 Java 8,正确的 处理方法如下:
// Decide what time zone you want to work in
ZoneId tz = ZoneId.of("Europe/Berlin");
// If you wanted the local time zone of the system,
// Use this instead:
// ZoneId tz = ZoneId.systemDefault();
// Get instants from the timestamps
Instant i1 = Instant.ofEpochMilli(1466062306000l);
Instant i2 = Instant.ofEpochMilli(1466028000000l);
// Get the calendar date in the specified time zone for each value
LocalDate d1 = i1.atZone(tz).toLocalDate();
LocalDate d2 = i2.atZone(tz).toLocalDate();
// Get the difference in days
long daysBetween = ChronoUnit.DAYS.between(d2, d1);
如果您的输入确实是 Calendar
对象而不是时间戳,我建议 Calendar.toInstant()
如 Legacy Date-Time Code 指南中所述。
如果您使用的是 Java 7 或更早版本,您会在 Joda Time 库中找到类似的功能。
如果您真的不想使用其中的任何一个,并且仍然以旧的(困难的)方式做事,那么请参阅 this example。