Преобразовать java.util.Date для какого типа "java.time"?
У меня есть java.util.Date
объект или java.util.Calendar
объект. Как мне преобразовать это в правильный тип в фреймворке java.time?
Я слышал, что теперь мы должны выполнять основную часть нашей бизнес-логики с типами java.time. При работе со старым кодом, который еще не обновлен для java.time, я должен иметь возможность конвертировать туда и обратно. Какие типы карт для java.util.Date
или же java.util.Calendar
?
1 ответ
Да, вам определенно следует использовать фреймворк java.time, когда это возможно.
Избегайте старых классов даты и времени
Старые классы даты и времени, включая java.util.Date
, java.util.Calendar
, а также java.text.SimpleTextFormat
и такие оказались плохо продуманными, запутанными и хлопотными. Избегайте их, где вы можете. Но когда вы должны взаимодействовать с этими старыми типами, вы можете конвертировать между старым и новым.
Продолжайте читать для базового введения, несколько упрощенного, чтобы ориентировать вас в перемещении назад и вперед между старым и новым классами даты и времени.
java.time
Инфраструктура java.time определяется JSR 310, вдохновлена чрезвычайно успешной библиотекой Joda-Time и расширена проектом ThreeTen-Extra. Большая часть функциональности была перенесена на Java 6 & 7 в проекте ThreeTen-Backport с дальнейшей адаптацией для Android в проекте ThreeTenABP.
Какой тип java.time соответствует java.util.Date
? Ну а java.util.Date
Объект в основном представляет момент на временной шкале в UTC, комбинацию даты и времени суток. Мы можем перевести это на любой из нескольких типов в java.time. Каждый обсуждается ниже. Обратите внимание, что некоторые старые методы были добавлены к старым классам даты и времени, чтобы облегчить преобразования.
UTC с разрешением наносекунд.
Как правило, вы должны делать большую часть своей бизнес-логики в UTC. В такой работе, Instant
будет использоваться часто. Пройти вокруг Instant
объекты, применяя часовой пояс только для представления пользователю. Если вам нужно применить смещение или часовой пояс, используйте типы, описанные ниже.
От java.util.Date
в Instant
Учитывая, что оба Instant
а также java.util.Date
момент на временной шкале в UTC, мы можем легко перейти от java.util.Date
для Instant
, Старый класс получил новый метод, java.util.Date::toInstant
,
Instant instant = myUtilDate.toInstant();
Вы можете пойти в другом направлении, от Instant
к java.util.Date
, Но вы можете потерять информацию о доли секунды. Instant
отслеживает наносекунды, до девяти цифр после десятичной точки, такие как 2016-01-23T12:34:56.123456789Z
, И java.util.Date &.Calendar ограничены миллисекундами, до трех цифр после десятичного знака, таких как 2016-01-23T12:34:56.123Z
, В этом примере происходит от Instant
в Date
означает усечение 456789
,
java.util.Date myUtilDate = java.util.Date.from( instant );
От java.util.Calendar
в Instant
Как насчет java.util.Calendar
вместо java.util.Date
? Внутренний для Calendar
объект даты время отслеживается как подсчет миллисекунд от опорной эпохи даты и времени первого момента в 1970 UTC (1970-01-01T00:00:00.0Z
). Таким образом, это значение может быть легко преобразовано в Instant
,
Instant instant = myUtilCalendar.toInstant() ;
От java.util.GregorianCalendar
в ZonedDateTime
Еще лучше, если ваш java.util.Calendar
объект на самом деле java.util.GregorianCalendar
Вы можете легко перейти прямо к ZonedDateTime
, Этот подход имеет преимущество сохранения встроенной информации о часовом поясе.
Даункаут с интерфейса Calendar
к конкретному классу GregorianCalendar
, Затем позвоните toZonedDateTime
а также from
методы, чтобы идти вперед и назад.
if( myUtilCalendar instanceof GregorianCalendar ) {
GregorianCalendar gregCal = (GregorianCalendar) myUtilCalendar; // Downcasting from the interface to the concrete class.
ZonedDateTime zdt = gregCal.toZonedDateTime(); // Create `ZonedDateTime` with same time zone info found in the `GregorianCalendar`
end if
Идти в другом направлении...
java.util.Calendar myUtilCalendar = java.util.GregorianCalendar.from( zdt ); // Produces an instant of `GregorianCalendar` which implements `Calendar` interface.
Как обсуждалось выше, будьте осторожны, что вы можете потерять информацию о доле секунды. Наносекунды в типе java.time (ZonedDateTime
) усекается до миллисекунд в .Calendar
/ .GregorianCalendar
,
OffsetDateTime
Из Instant
мы можем применить смещение от UTC, чтобы перейти во время настенных часов для некоторой местности. Смещение - это количество часов и, возможно, минут и секунд, перед UTC (на восток) или позади UTC (на запад). ZoneOffset
класс представляет эту идею. Результатом является OffsetDateTime
объект.
ZoneOffset offset = ZoneOffset.of( "-04:00" );
OffsetDateTime odt = OffsetDateTime.ofInstant( instant , zoneOffset );
Вы можете пойти в другом направлении, от OffsetDateTime
к java.util.Date
, Извлечь Instant
а затем продолжайте, как мы видели в коде выше. Как обсуждалось выше, любые наносекунды усекаются до миллисекунд (потеря данных).
java.util.Date myUtilDate = java.util.Date.from( odt.toInstant() );
ZonedDateTime
Еще лучше применить полный часовой пояс. Часовой пояс - это смещение плюс правила для обработки аномалий, таких как переход на летнее время (DST).
Применяя ZoneId
дает вам ZonedDateTime
объект. Используйте правильное название часового пояса (континент / регион). Никогда не используйте 3-4 буквенные сокращения, такие как EST
или же IST
поскольку они не стандартизированы и не уникальны.
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );
Вы можете пойти в другом направлении, от ZonedDateTime
к java.util.Date
, Извлечь Instant
а затем продолжайте, как мы видели в коде выше. Как обсуждалось выше, любые наносекунды усекаются до миллисекунд (потеря данных).
java.util.Date myUtilDate = java.util.Date.from( zdt.toInstant() );
И мы увидели выше, что ZonedDateTime
может быть преобразован в GregorianCalendar
,
LocalDate
Иногда вам может понадобиться значение только для даты, без времени суток и без часового пояса. Для этого используйте java.time.LocalDate
объект.
См. Этот вопрос для дальнейшего обсуждения. Преобразуйте java.util.Date в java.time.LocalDate, особенно этот ответ, написанный главным человеком, придумавшим изобретение Joda-Time и java.time.
Ключ должен пройти через ZonedDateTime
(как сгенерировано в коде выше). Нам нужен часовой пояс, чтобы определить дату. Дата меняется по всему миру, с новым днем на востоке. Например, после полуночи в Париже новый день, а в Монреале все еще "вчера". Так что пока LocalDate
не содержит часовой пояс, часовой пояс необходим для определения LocalDate
,
LocalDate localDate = zdt.toLocalDate();
Конвертировать в другом направлении от LocalDate
дата-время означает придумывать время суток. Вы можете выбрать любое время суток, которое имеет смысл в вашем бизнес-сценарии. Для большинства людей первый момент дня имеет смысл. Вы можете испытать желание написать жесткий код в этот первый момент, как время 00:00:00.0
, В некоторых часовых поясах это время может быть недействительным в качестве первого момента из-за перехода на летнее время (DST) или других аномалий. Так пусть java.time определит правильное время с помощью вызова atStartOfDay
,
ZonedDateTime zdt = localDate.atStartOfDay( zoneId );
LocalTime
В редких случаях вам может потребоваться только время суток без даты и без часового пояса. Эта концепция представлена LocalTime
учебный класс. Как обсуждено выше с LocalDate
нам нужен часовой пояс, чтобы определить LocalTime
хотя LocalTime
объект не содержит (не "запоминает") этот часовой пояс. Итак, снова мы проходим ZonedDateTime
объект, полученный из Instant
как видно выше.
LocalTime localTime = zdt.toLocalTime();
LocalDateTime
Как и с двумя другими Local…
типы, а LocalDateTime
не имеет ни часового пояса, ни смещения. Таким образом, вы можете использовать это редко. Это дает вам приблизительное представление о дате и времени, но не является точкой на временной шкале. Используйте это, если вы имеете в виду некоторую общую дату и время, которое может быть применено к часовому поясу.
Например, "Рождество начинается в этом году" будет 2016-12-25T00:00:00.0
, Обратите внимание на отсутствие какого-либо смещения или часового пояса в этом текстовом представлении LocalDateTime
, Рождество в Дели начинается раньше, чем в Париже во Франции, а позже - в Монреале, Квебеке, Канада. Применение часового пояса каждой из этих областей даст другой момент на временной шкале.
LocalDateTime ldt = zdt.toLocalDateTime();