Мгновенно против ZoneDateTime. Преобразование в другой часовой пояс

Мне трудно понять java.time между ZoneDateTime - Instant - LocalDateTime, пока единственное, о чем я знаю:

  • Мгновенно работает между двумя
  • Мгновенный (в моем понимании) - это штамп времени с момента времени (UTC), штамп времени, который имеет отношение к потоку человеческого времени, но без часового пояса.
  • Зона Дата время имеет часовой пояс
  • Instant не имеет часового пояса, но может работать с ним, учитывая, что предоставляется информация о зоне.
  • Время LocalDate не имеет часового пояса и не может иметь дело с зонами, это дата и время, не имеющее никакого отношения к продолжению всего потока времени (глобальное).

Итак, у меня есть это преобразование ниже

val seoul = "Asia/Seoul"

val zoneId = ZoneId.of(seoul)
val now = ZonedDateTime.now()

val convertedZoneDateTIme = ZonedDateTime.of(now.toLocalDateTime(), zoneId).withZoneSameInstant(ZoneOffset.UTC)
val convertedInstant = now.toInstant().atZone(zoneId)

// expected output
println(convertedInstant.format(DateTimeFormatter.ofPattern(format)))

// not expected output
println(converted.format(DateTimeFormatter.ofPattern(format)))

Вывод

2021-05-02 03:15:13
2021-05-02 09:15:13

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

Почему я получаю неверное значение на втором ..? Почему мне нужно сначала преобразовать его в Instant, а затем продолжить преобразование?

заранее спасибо


person ZyGabriel    schedule 02.05.2021    source источник
comment
Ваш convertInstant - это НЕ мгновение, а ZonedDateTime. Моя рекомендация: используйте явные типы вместо val. И выберите формат, показывающий часовой пояс. Тогда вы увидите, что первый результат находится в UTC, а второй результат - в южнокорейской зоне.   -  person Meno Hochschild    schedule 05.05.2021


Ответы (1)


Большинство ваших пуль полностью верны. Только вы не должны использовать Instant для работы между LocalDateTime и ZonedDateTime, как вы сказали в первом пункте. Для преобразования между Instant и LocalDateTime требуется часовой пояс (или, по крайней мере, смещение от UTC), поэтому следует использовать ZonedDateTime. Итак, ZonedDateTime - это то, что нужно использовать между двумя другими. Как я уже сказал, в остальном все правильно.

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

val convertedZoneDateTIme = ZonedDateTime.of(now.toLocalDateTime(), zoneId).withZoneSameInstant(ZoneOffset.UTC)

now - это ZonedDateTime в вашем собственном часовом поясе (если быть точным, часовой пояс вашей JVM по умолчанию). Взяв из него только дату и время дня и комбинируя их с другим часовым поясом, вы сохраняете время дня, но таким образом (возможно) меняете точку в потоке времени. Затем вы конвертируете в UTC, сохраняя точку во времени (момент), тем самым (возможно) изменяя время дня и, возможно, дату. У вас ничего не осталось от ZonedDateTime, которое было вашей отправной точкой, и я не вижу смысла в этой операции. Чтобы преобразовать now в UTC, сохраняя точку на временной шкале, используйте более простой способ:

val convertedZoneDateTIme = now.withZoneSameInstant(ZoneOffset.UTC)

С этим изменением ваши два выхода согласуются с моментом времени. Пример вывода:

2021-05-07 02:30:16 +09:00 Korean Standard Time
2021-05-06 17:30:16 +00:00 Z

Я использовал format из uuuu-MM-dd HH:mm:ss xxx zzzz.

Также для вас другое преобразование я бы предпочел использовать withZoneSameInstant(). Тогда нам не нужно проходить Instant.

val convertedInstant = now.withZoneSameInstant(zoneId)

Это дает тот же результат, что и ваш код.

Краткий обзор того, что есть в каждом из обсуждаемых классов:

Class Date and time of day Point in time Time zone
ZonedDateTime Yes Yes Yes
Instant - Yes -
LocalDateTime Yes - -

По сути, вы не можете использовать LocalDateTime для ваших целей, а также Instant, хотя и годный, в этом нет необходимости. Только ZonedDateTime удовлетворяет ваши потребности.

person Ole V.V.    schedule 06.05.2021
comment
Я еще не вернулся к своим тестам, но я очень ценю усилия, направленные на то, чтобы объяснить это мне кратко. Я не буду считать, что только ZonedDateTime может решить мою проблему с переключением из зоны в другую. - person ZyGabriel; 07.05.2021