Преобразование даты Java в OffsetDateTime

У меня есть значение eta, которое является OffsetDateTime, и у меня есть selectedDate, который является типом Date. Если эта не установлена, я хочу вернуться к дате.

Пример даты - Tue Jul 21 10:32:28 PDT 2020. Чтобы преобразовать это, я попытался сделать: OffsetDateTime.ofInstant(dto.getScheduledTime().ToInstant(), ZoneOffset.UTC) Кажется, что смещение utc неверно, поскольку в Date уже есть PDT, но в то же время это также не часовой пояс, как "America / Los_Angeles".

Я немного не понимаю, как с этим справиться.

Дата, есть ли в нет PDT. Строковая форма Date - отображается в местном часовом поясе вашей системы, но сам объект Date содержит миллисекунды с 1 января 1970 года, не более того. Вот почему вы должны указать часовой пояс. И UTC, вероятно, лучший выбор, если вашему приложению не требуется отображать его с определенным часовым поясом.

VGR 03.10.2018 20:03

Ага, ладно. Итак, единственная причина, по которой появился этот PDT, заключалась в том, что часовой пояс моей системы отсюда? На правильном ли я пути, используя функцию .ofInstant и пытаясь преобразовать scheduleTime в Instant?

user6728767 03.10.2018 20:05

Да, я считаю, что вы используете правильный подход для преобразования Date в OffsetDateTime.

VGR 03.10.2018 20:06

Хорошо, я не уверен, почему, но сегодня эта строка не возвращает null ... Может быть, я не сохранил в ide или что-то в этом роде. Но если вы говорите, что часовой пояс в строке недействителен для других мест, мне не следует использовать ZoneOffset.UTC, верно?

user6728767 03.10.2018 20:52

На мой взгляд, вам следует использовать UTC. Игнорировать строковую форму объектов Date; это не фактические данные, а просто удобный способ представления даты.

VGR 03.10.2018 20:56
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
11
5
21 460
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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 году.

table of date-time classes in Java, both legacy and modern

Используйте 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. Оба они представляют момент по всемирному координированному времени. Разница в том, что OffsetDateTime (a) может нести альтернативное значение смещения от UTC (часы-минуты-секунды), а (b) является более гибким, например, генерирует текст в форматах, отличных от стандартного ISO 8601.

Поймите, что offset-from-UTC - это просто количество часов, минут и секунд. Больше ничего. часовой пояс, напротив, больше много. Часовой пояс - это история прошлых, настоящих и будущих изменений смещения, используемого людьми определенного региона. Например, люди в регионе, использующие часовой пояс 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 есть часовой пояс, скрытый глубоко внутри. При отсутствии каких-либо методов доступа (get / set) он недоступен. Его поведение не имеет отношения к нашему обсуждению здесь. Сбивает с толку? да. Еще одна из многих причин избегать ужасных устаревших классов даты и времени.

Другие вопросы по теме