Короткий ответ:
Date in = new Date();
LocalDateTime ldt = LocalDateTime.ofInstant(in.toInstant(), ZoneId.systemDefault());
Date out = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());
Объяснение: ( на основе этого вопроса о LocalDate
)
Несмотря на свое название, java.util.Date
представляет собой момент времени, а не «дату». Фактические данные, хранящиеся в объекте, представляют собой long
количество миллисекунд с 1970-01-01T00: 00Z (полночь в начале 1970 года по Гринвичу / UTC).
Класс, эквивалентный классу java.util.Date
в JSR-310, есть Instant
, поэтому существуют удобные методы для обеспечения преобразования туда и обратно:
Date input = new Date();
Instant instant = input.toInstant();
Date output = Date.from(instant);
java.util.Date
Экземпляр не имеет понятия о времени зоны. Это может показаться странным , если вы звоните toString()
на java.util.Date
, потому что toString
это по отношению к часовому поясу. Однако этот метод на самом деле использует часовой пояс Java по умолчанию на лету для предоставления строки. Часовой пояс не является частью фактического состояния java.util.Date
.
Instant
Также не содержит никакой информации о часовом поясе. Таким образом, для преобразования из Instant
даты в местное время необходимо указать часовой пояс. Это может быть зона по умолчанию ZoneId.systemDefault()
- или это может быть часовой пояс, которым управляет ваше приложение, например часовой пояс из пользовательских настроек. LocalDateTime
имеет удобный заводской метод, который принимает как мгновенный, так и часовой пояс:
Date in = new Date();
LocalDateTime ldt = LocalDateTime.ofInstant(in.toInstant(), ZoneId.systemDefault());
И наоборот, LocalDateTime
часовой пояс указывается путем вызова atZone(ZoneId)
метода. Затем ZonedDateTime
можно преобразовать непосредственно в Instant
:
LocalDateTime ldt = ...
ZonedDateTime zdt = ldt.atZone(ZoneId.systemDefault());
Date output = Date.from(zdt.toInstant());
Обратите внимание, что преобразование из LocalDateTime
в ZonedDateTime
может привести к неожиданному поведению. Это связано с тем, что не каждое местное время существует из-за перехода на летнее время. Осенью / осенью местное время перекрывается, когда одна и та же местная дата-время встречается дважды. Весной есть разрыв, где час исчезает. Смотрите Javadoc atZone(ZoneId)
для более детального определения того, что будет делать преобразование.
Подводя итоги, если вы java.util.Date
совершите круговое путешествие от a до a LocalDateTime
и обратно к a, у java.util.Date
вас может получиться другое мгновение из-за перехода на летнее время.
Дополнительная информация: есть еще одно отличие, которое повлияет на очень старые даты. java.util.Date
использует календарь, который изменяется на 15 октября 1582 года с датами до этого, используя юлианский календарь вместо григорианского. Напротив, java.time.*
использует систему календаря ISO (эквивалент григорианского) для всех времен. В большинстве случаев используется календарная система ISO, но вы можете увидеть странные эффекты при сравнении дат до 1582 года.