Короткий ответ:
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 года.