Преобразование строки в метку времени Postgres и обратно

Часть 1:

У меня есть файл, содержащий дату в виде строки в следующем формате: 2006-02-16T21:36:32.000+0000

Мне нужно записать это значение в Postgres в столбце типа Timestamp. Как мне это сделать на Java?

Часть 2:

Мне нужно прочитать значение, сохраненное в части 1 из Postgres, и преобразовать его в строку следующего формата "2006-02-16T21:36:32.000+0000"


Вот что я пробовал:

Timestamp lastSyncDate = Timestamp.valueOf(2006-02-16T21:36:32.000+0000)

Когда я пытаюсь записать его в postgres, появляется следующая ошибка:

java.lang.IllegalArgumentException: Timestamp format must be yyyy-mm-dd hh:mm:ss[.fffffffff]

Не могли бы вы сделать тип этого столбца в Postgres timestamp with time zone? Поскольку ваша строка имеет смещение по всемирному координированному времени. +0000 означает смещение 0 от UTC. Если нет, вам, по крайней мере, нужно знать или решить часовой пояс или смещение UTC ваших временных меток. Если вы можете решить, я выберу UTC.

Ole V.V. 04.05.2018 05:52

Также избегайте класса Timestamp, он давно устарел. Вместо этого используйте java.time, современный API даты и времени Java. Из этого API лучше всего использовать Instant, если это возможно, как в Ответ Бэзила Бурка; если не пойдет, то LocalDateTime.

Ole V.V. 04.05.2018 08:52
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
2
2 652
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

2006-02-16T21:36:32.000+0000 выглядит как временная метка ISO-8601. postgres понимает этот формат. просто относитесь к ней как к любой другой строке.

не пытайтесь преобразовать его в метку времени Java

Фактически, передача этой строки в столбец типа TIMESTAMP (как указано в вопросе) приводит к потере данных. Смещение от UTC игнорируется и отбрасывается. Подробнее см. мой ответ.

Basil Bourque 04.05.2018 19:51
Ответ принят как подходящий

tl; dr

myPreparedStatement.setObject( 
    … , 
    OffsetDateTime.parse( "2006-02-16T21:36:32.000+0000" )  
) 

С и без зоны / смещения

Вы сказали, что ваша колонка относится к типу TIMESTAMP, что является сокращением от TIMESTAMP WITHOUT TIME ZONE. В этом типе намеренно отсутствует понятие часового пояса или смещения от UTC. Нет обычно подходит для общих деловых целей.

Вы используете неправильный тип

Это неправильный тип для вашего ввода. Ваш ввод имеет нулевое смещение от UTC, что означает сам UTC. Имея смещение или зону, ваши данные типа следует хранить только в TIMESTAMP WITH TIME ZONE столбец. В этом типе …WITH… в Postgres любая отправленная информация о смещении / зоне используется для корректировки в формате UTC для хранения, а затем отбрасывается.

Сохранение значения даты и времени со смещением или зоной в столбце типа TIMESTAMP WITHOUT TIME ZONE аналогично сохранению цены / стоимости в указанной валюте (доллары США, евро, рубли и т. д.) В столбце числового типа. Вы теряете жизненно важные данные, валюту. Это делает ваши данные бесполезными.

См. Страница документации Postgres для этих типов.

Умные объекты, а не глупые строки

По возможности используйте объекты для обмена данными с вашей базой данных, а не передавайте строки счетчиков. Пусть ваш Драйвер JDBC выполняет свою работу в маршалинг данных вперед и назад.

Разберите входную строку как объект OffsetDateTime.

ISO 8601

Ваши входные строки имеют формат, определенный стандартом ISO 8601. Классы java.time по умолчанию используют форматы ISO 8601 при синтаксическом анализе / генерации строк. Нет необходимости указывать шаблон форматирования.

String input = "2006-02-16T21:36:32.000+0000" ;
OffsetDateTime odt = OffsetDateTime.parse( input ) ;

Определите свой SQL как подготовленный оператор.

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

Вы можете передать OffsetDateTime. Мне нравится извлекать Instant, чтобы продемонстрировать читателю, что я понимаю, как Postgres всегда сохраняет значение TIMESTAMP WITH TIME ZONE в формате UTC.

Instant instant = odt.toInstant() ;
myPreparedStatement.setObject( … , instant ) ;

Извлечение.

Instant instant = myResultSet.getObject( … , Instant.class ) ;

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