tl; dr ⇒ используйте ZonedDateTime
для преобразования
public static void main(String[] args) {
// use your date here, this is just "now"
Date date = new Date();
// parse it to an object that is aware of the (currently wrong) time zone
ZonedDateTime wrongZoneZdt = ZonedDateTime.ofInstant(date.toInstant(), ZoneId.of("CET"));
// print it to see the result
System.out.println(wrongZoneZdt.format(DateTimeFormatter.ISO_ZONED_DATE_TIME));
// extract the information that should stay (only date and time, NOT zone or offset)
LocalDateTime ldt = wrongZoneZdt.toLocalDateTime();
// print it, too
System.out.println(ldt.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
// then take the object without zone information and simply add a zone
ZonedDateTime correctZoneZdt = ldt.atZone(ZoneId.of("GMT"));
// print the result
System.out.println(correctZoneZdt.format(DateTimeFormatter.ISO_ZONED_DATE_TIME));
}
Выход:
2020-01-24T09:21:37.167+01:00[CET]
2020-01-24T09:21:37.167
2020-01-24T09:21:37.167Z[GMT]
Объяснение:
Причиной, по которой ваш подход не только исправил зону, но и соответствующим образом скорректировал время (что хорошо при желании), является использование LocalDateTime
, созданного из Instant
. Instant
представляет момент времени, который может иметь разные представления в разных зонах, но он остается одним и тем же моментом. Если вы создадите LocalDateTime
из него и поместите другую зону, дата и время конвертируются в целевую зону. Это не просто замена зоны с сохранением даты и времени, как они есть.
Если вы используете LocalDateTime
из ZonedDateTime
, вы извлекаете представление даты и времени, игнорируя зону, что позволяет впоследствии добавить другую зону и сохранить дату и время такими, какими они были.
Редактировать: если код работает в той же JVM, что и неисправный код, вы можете использовать ZoneId.systemDefault()
, чтобы получить тот же часовой пояс, что и в неисправном коде. И в зависимости от вкуса вы можете использовать ZoneOffset.UTC
вместо ZoneId.of("GMT")
.