Есть ли разница между ними:
zonedDateTime.truncatedTo(ChronoUnit.DAYS);
zonedDateTime.toLocalDate().atStartOfDay(zonedDateTime.getZone());
Любые причины предпочесть друг другу?
Спасибо
Есть ли разница между ними:
zonedDateTime.truncatedTo(ChronoUnit.DAYS);
zonedDateTime.toLocalDate().atStartOfDay(zonedDateTime.getZone());
Любые причины предпочесть друг другу?
Спасибо
Обновлено для исправления:
В большинстве случаев да, тот же, см. следующий пример для Бразилии при переключении с зимнего на летнее время:
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
-part в заданном часовом поясе для этой ситуации фактически одинаково.
Однако для обратного случая перехода с летнего времени на зимнее время существует одно исключение (очень спасибо @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();
Они немного разные. Согласно 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);
который дает тот же результат, что и truncatedTo