Почему разница между 30 марта и 1 марта 2020 года ошибочно дает 28 дней вместо 29? - PullRequest
124 голосов
/ 05 февраля 2020
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.

Может ли быть проблема с часовым поясом / местоположением?

Ответы [ 2 ]

207 голосов
/ 05 февраля 2020

Проблема в том, что из-за перехода на летнее время (в воскресенье, 8 марта 2020 г.) между этими датами 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, например UT C:

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
41 голосов
/ 05 февраля 2020

Причина этой проблемы уже упоминалась в Ответ Андреаса .

Вопрос: что именно вы точно хотите посчитать. Тот факт, что вы утверждаете, что фактическая разница должна составлять 29 вместо 28, и спрашиваете, может ли «время местоположения / зона быть проблемой» , показывает, что вы на самом деле хотите считать. По-видимому, вы хотите избавиться от любой разницы часовых поясов.

Я предполагаю, что вы хотите рассчитывать только дни без времени и часового пояса.

Java 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);

Обратите внимание, что для ChronoUnit, DateTimeFormatter и LocalDate требуется не менее Java 8, что вам недоступно, согласно тегу . Тем не менее, это возможно для будущих читателей.

Как уже упоминал Оле В.В., есть также ThreeTen Backport , который ретранслирует Java 8 Date and Time API к Java 6 и 7.

...