tl; dr
OffsetDateTime target , eta ; // Modern java.time class.
java.util.Date scheduledDate ; // Terrible legacy class.
if( Objects.isNull( eta ) ) { // If no eta, fall back to scheduledDate.
target = scheduledDate.toInstant().atOffset( ZoneOffset.UTC ) ; // Never use legacy class `java.util.Date` -- when encountered, immediately convert to modern `java.time.Instant`.
} else { // Else not null.
target = eta ;
}
return target ;
Лучше полностью избегать java.util.Date
.При обнаружении немедленно преобразуйте в современный класс Instant
и забудьте все об объекте Date
.
OffsetDateTime target, eta, scheduled ;
scheduled = incomingJavaUtilDate.toInstant().atOffset( ZoneOffset.UTC ) ;
target = Objects.isNull( eta ) ? scheduledDate : eta ; // Ternary operator. Short way of saying: If eta is null, go with scheduledDate, otherwise go with eta.
return target ;
Date::toString
ложь вам
Во-первых, поймите, что java.util.Date
представляет момент в UTC, всегда в UTC † .Тем не менее, его метод toString
имеет благие намерения, потому что ужасно запутывает анти-функцию динамического применения текущего часового пояса JVM по умолчанию.Это создает ложное впечатление, что Date
имеет часовой пояс, когда на самом деле он не † .
Избегайте устаревших классов даты и времени
Во-вторых, вам не нужнои трагически смешивать очень хорошие современные java.time классы (OffsetDateTime
) с ужасно ужасными унаследованными классами даты и времени (Date
).Не делайте этого.Избегайте старых классов полностью.Они были устаревшими в результате принятия JSR 310 еще в 2014 году.
Использование java.time
Если вручен объект java.util.Date
, немедленно преобразуйте в java.time .Вызовите новые методы преобразования, добавленные к старым классам.Класс Instant
прямо заменяет Date
как момент в UTC, но с более высоким разрешением наносекунд по сравнению с миллисекундами.
Instant instant = myJavaUtilDate.toInstant() ; // Convert from legacy class to modern class.
Обычно вы должны отслеживать моменты в UTC.Вы можете сделать это как Instant
или как OffsetDateTime
со смещением, равным ZoneOffset.UTC
константе.
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ; // Same moment, no change in meaning whatsoever.
Специально для UTC здесь нет разницы между instant
и odt
в нашем коде.Они оба представляют момент в UTC.Разница в том, что OffsetDateTime
(a) может содержать альтернативное значение смещения от UTC (часы-минуты-секунды), а (b) является более гибким, например генерировать текст в форматах, отличных от стандартного ISO 8601.
Поймите, что смещение от UTC - это просто количество часов, минут и секунд.Ничего более.A часовой пояс , напротив, на намного больше.Часовой пояс - это история прошлых, настоящих и будущих изменений в смещении, используемом людьми определенного региона.Например, люди в регионе, использующие America/Los_Angeles
часовой пояс, меняют свое смещение от UTC два раза в год в глупой практике, известной как Летнее время (DST) , переходящей с -08: 00 на -07: 00 и обратно.
Так что обычно часовой пояс предпочтительнее простого смещения.Например, чтобы увидеть ваше Date
, которое мы превратили в Instant
через настенное время, используемое большинством людей на западном побережье США, примените часовой пояс America/Los_Angeles
(ZoneId
) к Instant
чтобы получить ZonedDateTime
.
ZoneId z = ZoneId.of( "America/Los_Angeles" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
Вы можете вернуться в UTC, извлекая Instant
.
Instant instant = zdt.toInstant() ;
И оттуда вернитесь к java.util.Date
(если необходимо, иначе избегайте).
java.util.Date d = java.util.Date.from( instant ) ;
† На самом деле,java.time.Date
класс имеет часовой пояс, скрытый глубоко внутри.Не имея каких-либо методов доступа (получить / установить), он недоступен.Его поведение не имеет отношения к нашему обсуждению здесь.Смешение?Да.Еще одна из многих причин избегать ужасных устаревших классов даты и времени.