Java.time эквивалент Joda-Time `withTimeAtStartOfDay`? (получить первый момент дня)

В библиотеке Joda-Time класс DateTime предлагает метод withTimeAtStartOfDay, чтобы получить первый момент дня. Вы могли бы подумать, что этот момент "полночь". Этот первый момент обычно равен времени 00:00:00.000, но не всегда.

Есть ли пакет java.time, найденный в Java 8 и более поздних версиях, эквивалентной?

Ответ 1

Эквивалент использует специальный метод atStartOfDay, в классе LocalDate:

ZoneId zoneId = ZoneId.of("America/New_York");
ZonedDateTime zdt = LocalDate.now(zoneId).atStartOfDay(zoneId);

Также обратите внимание, что эквивалент Joda-Time DateTime не LocalDateTime, но ZonedDateTime. Здесь имеет значение параметр zoneId. Конкретный пример миграции - см. Также веб-сайт часового пояса для получения более подробной информации о Летнее время ( DST) в Бразилии:

Joda-Time (старый способ)

DateTime dt = 
  new DateTime(2015, 10, 18, 12, 0, DateTimeZone.forID("America/Sao_Paulo"));
dt = dt.withTimeAtStartOfDay();
System.out.println(dt); // 2015-10-18T01:00:00.000-02:00

Обратите внимание, что этот код даже выдавал исключение для полуночи в первой строке с вызовом конструктор.

java.time(новый способ)

ZoneId zoneId = ZoneId.of("America/Sao_Paulo");
ZonedDateTime zdt =
  ZonedDateTime.of(2015, 10, 18, 12, 0, 0, 0, zoneId);
zdt = zdt.toLocalDate().atStartOfDay(zoneId);
System.out.println(zdt); // 2015-10-18T01:00-02:00[America/Sao_Paulo]

Второй программный оператор ведет себя иначе, чем Joda-Time, потому что он не будет генерировать исключение, но молча переключает местное время на размер пробела, о котором идет речь, здесь один час. Это означает, что если бы вы выбрали полночь, результат был бы таким же (а именно в 1:00). Если вы выбрали 00:30, тогда результат будет 01:30. Приведенный выше пример выбирает полдень в качестве входных данных.

Чтобы процитировать документ для ZonedDateTime.of(...):

В большинстве случаев существует только одно допустимое смещение для локальной даты-времени. В случае перекрытия, когда часы установлены назад, существуют два допустимых смещения. Этот метод использует более раннее смещение, обычно соответствующее "лету".

В случае зазора, когда часы переходят вперед, нет действительного смещения. Вместо этого локальная дата-время настраивается на более позднюю длину пробела. Для типичного изменения дневного перехода на 1 час местное время-время будет перемещено на один час позже в смещение, обычно соответствующее "летнему".

100% -изменение всех данных, таких как поведение исключений и применяемые стратегии перехода DST, невозможно, потому что обе библиотеки слишком разные. Но это ваше руководство:

  • заменить DateTime на ZonedDateTime
  • рассмотрим возможность переключения на LocalDate для промежуточных вычислений (см. пример)
  • используйте явные ссылки на часовой пояс и замените DateTimeZone на zoneId

Ответ 2

Вы можете использовать LocalDate для этого:

// or a similar factory method to get the date you want
LocalDateTime startOfDay = LocalDate.now().atStartOfDay();

Объединяет эту дату со временем полуночи, чтобы создать LocalDateTime в начале этой даты. Это возвращает значение LocalDateTime, сформированное с этой даты во время полуночи, 00:00, в начале этой даты.

https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html#atStartOfDay--

Ответ 3

Обрезать

Хотя это старый вопрос, я только что открыл другой способ сделать это, используя усечение, которое мне кажется более элегантным

ZonedDateTime now = ZonedDateTime.now();
ZonedDateTime today = now.truncateTo(ChronoUnit.DAYS); // today, midnight

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

Ответ 4

TemporalAdjuster

Каждый LocalTime также является TemporalAdjuster, поэтому если его можно передать методу with() большинства временных типов и обновить поля времени, которые будут соответствовать.

То есть:

@Test
public void date_time_at_start_of_day() throws Exception {
    assertThat(LocalDateTime.parse("2015-05-22T12:27:00")
                            .with(LocalTime.MIDNIGHT),
               equalTo(LocalDateTime.parse("2015-05-22T00:00:00")));
    assertThat(OffsetDateTime.parse("2015-05-22T12:27:00+01:00")
                             .with(LocalTime.MIDNIGHT),
               equalTo(OffsetDateTime.parse("2015-05-22T00:00:00+01:00")));
    assertThat(ZonedDateTime.parse("2015-05-22T12:27:00+01:00[Europe/London]")
                            .with(LocalTime.MIDNIGHT),
               equalTo(ZonedDateTime.parse("2015-05-22T00:00:00+01:00[Europe/London]")));
}