Why does the difference between 30 March and 1 March 2020 erroneously give 28 days instead of 29?

TimeUnit.DAYS.convert(
Math.abs(
new SimpleDateFormat("dd-MM-yyyy HH:mm:ss").parse("30-03-2020 00:00:00").getTime() -
new SimpleDateFormat("dd-MM-yyyy HH:mm:ss").parse("1-03-2020 00:00:00").getTime()
),
TimeUnit.MILLISECONDS)

The result is 28, while it should be 29.

Could the time zone/location be the problem?

14636 次浏览

问题在于,由于夏时制(2020年3月8日,星期日)的变化,这两个日期之间存在 28天23小时TimeUnit.DAYS.convert(...) 截断的结果为28天。

看看问题(我在美国东部时区) :

SimpleDateFormat fmt = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
long diff = fmt.parse("30-03-2020 00:00:00").getTime() -
fmt.parse("1-03-2020 00:00:00").getTime();


System.out.println(diff);
System.out.println("Days: " + TimeUnit.DAYS.convert(Math.abs(diff), TimeUnit.MILLISECONDS));
System.out.println("Hours: " + TimeUnit.HOURS.convert(Math.abs(diff), TimeUnit.MILLISECONDS));
System.out.println("Days: " + TimeUnit.HOURS.convert(Math.abs(diff), TimeUnit.MILLISECONDS) / 24.0);

输出

2502000000
Days: 28
Hours: 695
Days: 28.958333333333332

要解决这个问题,可以使用一个没有 DST 的时区,例如 协调世界时:

SimpleDateFormat fmt = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
fmt.setTimeZone(TimeZone.getTimeZone("UTC"));
long diff = fmt.parse("30-03-2020 00:00:00").getTime() -
fmt.parse("1-03-2020 00:00:00").getTime();

输出

2505600000
Days: 29
Hours: 696
Days: 29.0

这个问题的原因在 安德里亚斯的回答中已经提到了。

问题是 什么正是你想要数的。你声明实际的差值应该是29而不是28,并且询问 “地点/区域时间可能是个问题”是否揭示了你实际想要计数的东西。显然,你想摆脱所有的时区差异。

我假设您只想计算天数,而不想计算时间和时区。

爪哇8

下面的例子说明了如何正确地计算两者之间的天数,我正在使用一个类来精确地表示这个日期——一个没有时间和时区的日期—— LocalDate

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d-MM-yyyy HH:mm:ss");
LocalDate start = LocalDate.parse("1-03-2020 00:00:00", formatter);
LocalDate end = LocalDate.parse("30-03-2020 00:00:00", formatter);


long daysBetween = ChronoUnit.DAYS.between(start, end);

请注意,根据 标记,ChronoUnitDateTimeFormatterLocalDate至少需要 Java8,而 Java8不可用。然而,对于未来的读者来说也许是这样的。

正如 Ole V.V. 提到的,还有 310后端口,它将 Java8的 Date 和 Time API 功能支持到 Java6和 Java7。