为什么2020年3月30日和3月1日之间的差异错误地给出了28天而不是29天?

2022-08-31 08:30:20
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)

结果为 28,而应为 29。

时区/位置可能是问题所在吗?


答案 1

问题是,由于夏令时偏移(2020年3月8日星期日),这些日期之间有28天23小时。 将结果截断为 28 天。TimeUnit.DAYS.convert(...)

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

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 的时区,例如 UTC

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

答案 2

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

问题是你到底想算什么。您声明实际差异应为 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);

请注意,根据 标记,至少需要 Java 8,这对你来说不可用。但是,它也许是给未来的读者的。ChronoUnitDateTimeFormatterLocalDate

正如Ole V.V.所提到的,还有ThreeTen Backport,它将Java 8日期和时间API功能反向移植到Java 6和7。