Время UTC в базе данных, тип которой «отметка времени без часового пояса», чтобы показать в UTC в ответ - PullRequest
0 голосов
/ 06 июня 2018

У меня есть поле в postgres, тип которого "метка времени без часового пояса".Это время UTC в базе данных, которое я хочу показать в ответе API.

Я использовал следующий код, чтобы показать его в том же часовом поясе UTC, но он добавляет мое локальное смещение времени в ответе API -

// date from db in UTC is 2018-06-06 09:59:04.103
Date createdDateTime = description.getCreatedDateTime();
SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
isoFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
try {
        Date date = isoFormat.parse(createdDateTime.toString());
        description.setCreatedDateTime(date);
        } catch (ParseException e) {
            LOGGER.error("An exception has occured in parsing .", e);
        }

Мое время создания в IST- 2018-06-06 15:16:04.103 IST Я все еще получаю вывод со смещением в ответ: Jun 6, 2018 8:46:52 PM

Я использую hibernate для извлечения данных из таблицы.

Ответы [ 2 ]

0 голосов
/ 07 июня 2018

java.util.Date::toString применяет зону

Вероятно, вас смущает благонамеренное, но неудачное проектное решение метода java.util.Date::toString для динамического применения текущего часового пояса JVM по умолчанию при создании строки для представлениязначение Date, которое на самом деле всегда в UTC по определению.Одна из многих причин избежать этого ужасно неприятного старого класса.

Неправильный тип данных в базе данных

У меня есть поле в postgres, тип которого "отметка времени безчасовой пояс".Время UTC в базе данных, которое я хочу показать в ответе API.

Это противоречие в терминах.Стандартный столбец SQL TIMESTAMP WITHOUT TIME ZONE не содержит значения UTC.В этом типе данных отсутствует понятие часового пояса или смещения от UTC.(Такие значения UTC должны были бы вместо этого быть сохранены в столбце типа TIMESTAMP WITH TIME ZONE.)

Возможно, вы вставили значения, которые предназначались для UTC, но вы потеряли этот факт, когда-то сохранялись вбаза данных.

java.time

Избегать java.sql.Timestamp

Существует нет необходимо использовать java.sql.Timestamp.Этого унаследованного класса следует избегать.Начиная с JDBC 4.2 и более поздних версий, мы можем напрямую обмениваться типами java.time с базой данных. Hibernate поддерживает java.time .

LocalDateTime

При отсутствии какой-либо зоны / смещения вы должны получить эти значения, используя LocalDateTime класс.В этом классе также отсутствует понятие часового пояса или смещения от UTC.

LocalDateTime ldt = myResultSet.getObject( … , LocalDateTime.class ) ;

OffsetDateTime

Если вы хотите предположить , что полученное значение представляет собоймомент в UTC, примените ZoneOffset, чтобы получить OffsetDateTime объект.В частности, для UTC мы можем использовать предопределенную константу ZoneOffset.UTC.

OffsetDateTime odt = ldt.atOffset( ZoneOffset.UTC ) ;

Not ZonedDateTime

В то время как класс ZonedDateTime будет технически работать здесь, вместо класса OffsetDateTime, его использование неуместно.

Часовой пояс намного больше, чем смещение.Зона - это история прошлых, настоящих и будущих изменений в смещении, используемом людьми определенного региона.Напротив, смещение от UTC - это просто количество часов и минут, ни больше, ни меньше.

Таким образом, использование ZonedDateTime в этом контексте UTC вводит в заблуждение и может привести к путанице.

Instant

Теперь в вашем OffsetDateTime объекте у вас естьмомент в UTC.

Если вы знаете, что оттуда хотите работать только в UTC, извлеките Instant.Instant всегда в UTC по определению.Для представления моментов в UTC обычно используйте Instant.Если вам нужна большая гибкость, например, при генерации строк в различных форматах, переключитесь на использование OffsetDateTime.

Instant instant = odt.toInstant() ;

О java.time

Среда java.time встроена в Java 8и позже.Эти классы вытесняют проблемные старые устаревшие классы даты и времени, такие как java.util.Date, Calendar, & SimpleDateFormat.

Проект Joda-Time , теперь в режиме обслуживания , рекомендует перейти на классы java.time .

Чтобы узнать больше, см. Oracle Tutorial .И поиск переполнения стека для многих примеров и объяснений.Спецификация: JSR 310 .

Вы можете обмениваться java.time объектами напрямую с вашей базой данных.Используйте драйвер JDBC , совместимый с JDBC 4.2 или более поздней версии.Нет необходимости в строках, нет необходимости в java.sql.* классах.

Где получить классы java.time?

  • Java SE 8 , Java SE 9 , Java SE 10, а позже
    • Встроенный.
    • Часть стандартного Java API с встроенной реализацией.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 и Java SE 7
    • Большая часть функций java.time перенесена на Java 6 и 7 в ThreeTen-Backport .
  • Android
    • Более поздние версии Android связывают реализации классов java.time.
    • Для более ранних версий Android (<26)<a href="https://github.com/JakeWharton/ThreeTenABP" rel="nofollow noreferrer"> ThreeTenABP проект адаптируется ThreeTen-Backport (упомянуто выше).См. Как использовать ThreeTenABP… .

ThreeTen-Extra Проект расширяет java.time дополнительными классами.Этот проект является полигоном для возможных будущих дополнений к java.time.Здесь вы можете найти некоторые полезные классы, такие как Interval, YearWeek, YearQuarter и more .

0 голосов
/ 06 июня 2018

Этот тип столбца должен возвращать тип Timestamp в Java (или LocalDateTime с JDBC 4.2+).Эта временная метка будет содержать исходную дату, но в вашем часовом поясе по умолчанию.Поэтому вам нужно применить часовой пояс UTC к нему.

java.sql.Timestamp t = ...;
ZonedDateTime zdt = t.toLocalDateTime() //remove time zone information
                     .atZone(ZoneOffset.UTC); //this is actually a UTC time

На этом этапе вы можете продолжать использовать java.time объекты (без причины, если можете), или вы можете преобразовать ZonedDateTime вjava.util.Date с:

java.util.Date date = Date.from(zdt.toInstant());
...