Java 8 имеет совершенно новый API для даты и времени. Одним из наиболее полезных классов в этом API является LocalDateTime
хранение значения даты со временем, не зависящего от часового пояса.
Вероятно, существуют миллионы строк кода, использующих устаревший класс java.util.Date
для этой цели. Таким образом, при взаимодействии старого и нового кода будет необходимо преобразование между ними. Как, кажется, нет прямых методов для достижения этой цели, как это можно сделать?
Ответы:
Короткий ответ:
Объяснение: ( на основе этого вопроса о
LocalDate
)Несмотря на свое название,
java.util.Date
представляет собой момент времени, а не «дату». Фактические данные, хранящиеся в объекте, представляют собойlong
количество миллисекунд с 1970-01-01T00: 00Z (полночь в начале 1970 года по Гринвичу / UTC).Класс, эквивалентный классу
java.util.Date
в JSR-310, естьInstant
, поэтому существуют удобные методы для обеспечения преобразования туда и обратно:java.util.Date
Экземпляр не имеет понятия о времени зоны. Это может показаться странным , если вы звонитеtoString()
наjava.util.Date
, потому чтоtoString
это по отношению к часовому поясу. Однако этот метод на самом деле использует часовой пояс Java по умолчанию на лету для предоставления строки. Часовой пояс не является частью фактического состоянияjava.util.Date
.Instant
Также не содержит никакой информации о часовом поясе. Таким образом, для преобразования изInstant
даты в местное время необходимо указать часовой пояс. Это может быть зона по умолчаниюZoneId.systemDefault()
- или это может быть часовой пояс, которым управляет ваше приложение, например часовой пояс из пользовательских настроек.LocalDateTime
имеет удобный заводской метод, который принимает как мгновенный, так и часовой пояс:И наоборот,
LocalDateTime
часовой пояс указывается путем вызоваatZone(ZoneId)
метода. ЗатемZonedDateTime
можно преобразовать непосредственно вInstant
:Обратите внимание, что преобразование из
LocalDateTime
вZonedDateTime
может привести к неожиданному поведению. Это связано с тем, что не каждое местное время существует из-за перехода на летнее время. Осенью / осенью местное время перекрывается, когда одна и та же местная дата-время встречается дважды. Весной есть разрыв, где час исчезает. Смотрите JavadocatZone(ZoneId)
для более детального определения того, что будет делать преобразование.Подводя итоги, если вы
java.util.Date
совершите круговое путешествие от a до aLocalDateTime
и обратно к a, уjava.util.Date
вас может получиться другое мгновение из-за перехода на летнее время.Дополнительная информация: есть еще одно отличие, которое повлияет на очень старые даты.
java.util.Date
использует календарь, который изменяется на 15 октября 1582 года с датами до этого, используя юлианский календарь вместо григорианского. Напротив,java.time.*
использует систему календаря ISO (эквивалент григорианского) для всех времен. В большинстве случаев используется календарная система ISO, но вы можете увидеть странные эффекты при сравнении дат до 1582 года.источник
java.util.Date
не содержит часовой пояс, но печатайте его во времяtoString()
. Официальная документация события не говорит это ясно, как вы публикуете.LocalDateTime.ofInstant(date.toInstant()...
не ведет себя так, как можно наивно ожидать. Напримерnew Date(1111-1900,11-1,11,0,0,0);
, станет1111-11-17 23:53:28
использовать этот подход. Посмотрите на реализацию,java.sql.Timestamp#toLocalDateTime()
если вам нужно, чтобы результат был1111-11-11 00:00:00
в предыдущем примере.java.sql.Date#toInstant
выбрасываетUnsupportedOperationException
. Так что не используйтеtoInstant
в RowMapper наjava.sql.ResultSet#getDate
.Вот то, что я придумал (и, как и все загадки Date Time, это, вероятно, будет опровергнуто на основании некоторой странной корректировки timezone-leapyear-daylight: D)
Отключение:
Date
<< - >>LocalDateTime
Данный:
Date date = [some date]
(1)
LocalDateTime
<<Instant
<<Date
(2)
Date
<<Instant
<<LocalDateTime
Пример:
Данный:
(1)
LocalDateTime
<<Instant
<<Date
:Создать
Instant
изDate
:Создайте
Date
изInstant
(не обязательно, но для иллюстрации):Создать
LocalDateTime
изInstant
(2)
Date
<<Instant
<<LocalDateTime
Создать
Instant
изLocalDateTime
:Создать
Date
изInstant
:Выход:
источник
Instant.ofEpochMilli(date.getTime())
делатьdate.toInstant()
toInstant()
выглядит красиво, за исключением того, что это не такjava.sql.Date
, arggggh! Так что, наконец, проще в использованииInstant.ofEpochMilli(date.getTime())
.Гораздо более удобный способ, если вы уверены, что вам нужен часовой пояс по умолчанию:
источник
Кажется, что следующее работает при преобразовании из нового API LocalDateTime в java.util.date:
обратное преобразование может быть (надеюсь) достигнуто аналогичным способом ...
Надеюсь, поможет...
источник
Все здесь: http://blog.progs.be/542/date-to-java-time
Ответ с «круговым отключением» не является точным: когда вы делаете
если ваш системный часовой пояс не UTC / GMT, вы меняете время!
источник
Самый быстрый способ для
LocalDateTime
->Date
это:Date.from(ldt.toInstant(ZoneOffset.UTC))
источник
Я не уверен, если это самый простой или лучший способ, или есть какие-либо подводные камни, но это работает:
источник
LocalDateTime
вDate
. При переходах на летнее время, aLocalDateTime
может отсутствовать или встречаться дважды. Вы должны решить, что вы хотите, чтобы произошло в каждом случае.GregorianCalendar
принадлежит старый неуклюжий API, который новыйjava.time
API стремится заменитьЕсли вы работаете на Android и используете threetenbp, вы можете использовать
DateTimeUtils
вместо этого.например:
вы не можете использовать,
Date.from
так как он поддерживается только на API 26+источник