Многие объяснения уже присутствуют, чтобы объяснить, как это происходит и как это исправить, но вы также должны следовать рекомендациям, чтобы избежать NullPointerException
вообще.
См. также: A хороший список лучших практик
Я бы добавил, очень важно, хорошо использовать модификатор final
. Использование "окончательной" модификатор, когда это применимо в Java
Сводка:
final
для обеспечения хорошей инициализации. @NotNull
и @Nullable
if("knownObject".equals(unknownObject)
valueOf()
поверх toString (). StringUtils
StringUtils.isEmpty(null)
. Обновлено для исправления:
В большинстве случаев да, то же самое, см. следующий пример для Бразилии при переключении с зимнего на летнее время:
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 общая стратегия заключается в том, что если локальная дата-время попадает в середину перекрытия, тогда предыдущее смещение будет сохранено. Если предыдущее смещение не было, или предыдущее смещение недействительно, используется более раннее смещение, обычно «летнее» время.
blockquote>Если класс
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();
Они немного отличаются. Согласно 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]
Обратите внимание, что есть и другой способ сделать это:
zonedDateTime.with(LocalTime.MIN);
, который дает тот же результат, что и усеченный To