Как вернуть значение полуночи (начало дня) для переменной ZonedDateTime [duplicate]

Многие объяснения уже присутствуют, чтобы объяснить, как это происходит и как это исправить, но вы также должны следовать рекомендациям, чтобы избежать NullPointerException вообще.

См. также: A хороший список лучших практик

Я бы добавил, очень важно, хорошо использовать модификатор final. Использование "окончательной" модификатор, когда это применимо в Java

Сводка:

  1. Используйте модификатор final для обеспечения хорошей инициализации.
  2. Избегайте возврата null в методы, например, при возврате пустых коллекций.
  3. Использовать аннотации @NotNull и @Nullable
  4. Быстрое завершение работы и использование утверждений, чтобы избежать распространения нулевых объектов через все приложение, когда они не должен быть пустым.
  5. Сначала используйте значения с известным объектом: if("knownObject".equals(unknownObject)
  6. Предпочитают valueOf() поверх toString ().
  7. Используйте null safe StringUtils StringUtils.isEmpty(null).

38
задан JodaStephen 24 July 2015 в 09:45
поделиться

3 ответа

Обновлено для исправления:

В большинстве случаев да, то же самое, см. следующий пример для Бразилии при переключении с зимнего на летнее время:

ZonedDateTime zdt = 
  ZonedDateTime.of(2015, 10, 18, 0, 30, 0, 0, 
    ZoneId.of("America/Sao_Paulo")); // switch to summer time
ZonedDateTime zdt1 = zdt.truncatedTo(ChronoUnit.DAYS);
ZonedDateTime zdt2 = zdt.toLocalDate().atStartOfDay(zdt.getZone());

System.out.println(zdt); // 2015-10-18T01:30-02:00[America/Sao_Paulo]
System.out.println(zdt1); // 2015-10-18T01:00-02:00[America/Sao_Paulo]
System.out.println(zdt2); // 2015-10-18T01:00-02:00[America/Sao_Paulo]

Усечение происходит на местный график. Если вы выберете DAYS, тогда вы выбираете полночь. Согласно javadoc , truncate() -метод, наконец, обращается к новому ZonedDateTime и сдвигает время вперед на размер зазора (1 час).

Преобразование zdt сперва до LocalDate (отключение временной части), а затем поиск его ZonedDateTime -пары в заданном часовом поясе фактически одинаково для этой ситуации.

Однако для обратного случая возврата от летнего времени до зимнего времени есть одно исключение (спасибо очень большое спасибо @Austin, который дал встречный пример). Проблема заключается в перекрытии, когда нужно решить, какое смещение использовать. Обычно класс ZonedDateTime спроектирован / задан для использования предыдущего смещения, см. Также этот отрывок из Javadoc :

Для Overlaps общая стратегия заключается в том, что если локальная дата-время попадает в середину перекрытия, тогда предыдущее смещение будет сохранено. Если предыдущее смещение не было, или предыдущее смещение недействительно, используется более раннее смещение, обычно «летнее» время.

Если класс ZonedDateTime, следовательно, будет следовать своей собственной спецификации то обе процедуры все равно будут эквивалентными значениям:

zdt.truncatedTo(ChronoUnit.DAYS);

должен быть эквивалентен

zdt.toLocalDate().atStartOfDay().atZone(zdt.getZone()).withEarlierOffsetAtOverlap();

Но реальное поведение в соответствии с примером @Austin и подтверждено мной в собственном тестирование:

zdt.toLocalDate().atStartOfDay().atZone(zdt.getZone()).withLaterOffsetAtOverlap();

Похоже на скрытую несогласованность в классе ZonedDateTime, мягко говоря. Если вы спросите меня, какой метод будет предпочтительнее, я предпочел бы защищать второй метод, хотя он намного длиннее и требует больше нажатий клавиш. Но у него есть большое преимущество, чтобы быть более прозрачным в отношении того, что он делает. Еще одна причина предпочесть второй подход:

Он действительно получает ПЕРВЫЙ момент, когда местное время равно началу дня. В противном случае при использовании первого метода вам необходимо написать:

zdt.truncatedTo(ChronoUnit.DAYS).withEarlierOffsetAtOverlap();
36
ответ дан Meno Hochschild 19 August 2018 в 05:12
поделиться
  • 1
    Это не всегда правильно! См. Мой ответ, почему нет. – Austin 13 January 2017 в 01:54
  • 2
    @Austin. Ваш ответ кажется правдоподобным. Я буду расследовать и исправлять свой ответ соответственно. – Meno Hochschild 13 January 2017 в 08:46

Они немного отличаются. Согласно javadocs, truncatedTo() попытается сохранить часовой пояс в случае перекрытия, но atStartOfDay() найдет первое появление полуночи.

Например, Куба возвращает летнее сбережение в 1 утра, возвращаясь к 12 часам утра. Если вы начинаете со времени после этого перехода, atStartOfDay() вернет первое появление 12am, а truncatedTo() вернет второе появление.

ZonedDateTime zdt = ZonedDateTime.of(2016, 11, 6, 2, 0, 0, 0, ZoneId.of("America/Havana"));
ZonedDateTime zdt1 = zdt.truncatedTo(ChronoUnit.DAYS);
ZonedDateTime zdt2 = zdt.toLocalDate().atStartOfDay(zdt.getZone());

System.out.println(zdt);  // 2016-11-06T02:00-05:00[America/Havana]
System.out.println(zdt1); // 2016-11-06T00:00-05:00[America/Havana]
System.out.println(zdt2); // 2016-11-06T00:00-04:00[America/Havana]
25
ответ дан Austin 19 August 2018 в 05:12
поделиться
  • 1
    Большое спасибо за то, что вы нашли встречный пример. Отказались от вас, а также обновили свой ответ. – Meno Hochschild 13 January 2017 в 11:48

Обратите внимание, что есть и другой способ сделать это:

zonedDateTime.with(LocalTime.MIN);

, который дает тот же результат, что и усеченный To

4
ответ дан nevster 19 August 2018 в 05:12
поделиться
  • 1
    Как это будет вести себя в случае, когда летнее время (DST) начинается в полночь, то есть день начинается в 01:00? В любом случае код не выражает желаемого поведения в этом случае. – Ole V.V. 7 June 2018 в 06:21
  • 2
    Он будет вести себя так, как должен - то есть будет производить полуночи 00:00 в этот часовой пояс (что является подходящей временной зоной DST) Например, 2018-01-27T00: 00 + 11: 00 [Австралия / Сидней] против 2018-06-27T00: 00 +10: 00 [Австралия / Сидней] Вы получите тот же результат из всех 3 методов - 2 в исходном вопросе и эту более короткую версию – nevster 12 June 2018 в 01:44
  • 3
    На самом деле, чтобы уточнить, этот результат дает тот же результат, что и версия ChronoUnit.DAYS для углового случая – nevster 12 June 2018 в 01:53
Другие вопросы по тегам:

Похожие вопросы: