ТЛ; др
Postgres всегда сохраняет момент в UTC в столбце типа TIMESTAMP WITH TIME ZONE
.
- Заходя в базу данных, настроен на UTC.
- Ухожу, UTC.
Остерегайтесь инструмента доступа к базе данных : он может изменить полученное значение UTC, применяя настройку зоны / смещения. Это создает иллюзию того, что момент был сохранен в этой зоне / смещении, когда фактически он был сохранен в UTC.
Используйте объекты, а не строки для обмена значениями даты и времени с вашей базой данных.
Используйте только java.time классы, никогда не наследуйте Date
/ Calendar
. Для моментов UTC используйте java.time.Instant
класс.
Instant instant = Instant.now() ;
myPreparedStatement.setObject( … , instant ) ;
индексирование.
Instant instant = myResultSet.getObject( … , Instant.class ) ;
Умные объекты, а не тупые нити
Другие ответы правильны, когда советуют использовать объекты, а не строки при обмене значениями времени и даты между Java и вашей базой данных. В этом весь смысл JDBC и вашего драйвера JDBC , маршальных данных туда-сюда при передаче различий и деталей.
Однако эти другие ответы неправильно рекомендуют неправильные классы для использования в Java.
UTC
Postgres сохраняет моменты только в UTC . Любая информация о часовом поясе или смещении от UTC, сопровождающая ввод в столбец базы данных типа TIMESTAMP WITH TIME ZONE
, используется для корректировки значения в UTC. Затем значение UTC сохраняется в базе данных, а исходная зона / смещение забываются.
Аналогично, при извлечении значения из столбца базы данных типа TIMESTAMP WITH TIME ZONE
вы всегда получаете значение в UTC.
Тем не менее, ваше промежуточное программное обеспечение или инструмент, используемый между вами и базой данных, может быть выбран для изменения значения UTC при передаче, чтобы применить часовой пояс или смещение, тем самым корректируя значение. Я считаю, что это плохой выбор дизайна, хотя я понимаю благие намерения. Но такое поведение создает иллюзию, что зона / смещение были в сохраненных данных, когда их не было.
Имейте в виду, что я описываю поведение Postgres здесь. Стандарт SQL определяет типы данных, которые я здесь обсуждаю, но не их поведение. К сожалению, стандарт SQL почти не затрагивает вопросы даты и времени. Таким образом, различные реализации базы данных отличаются по своему поведению. Поведение Postgres с учетом UTC имеет для меня смысл. Но учтите, что если вас волнует исходная зона / смещение значения даты и времени, вы должны хранить их в отдельном столбце.
На стороне Java просто используйте Instant
для отправки и извлечения момента из столбца базы данных типа TIMESTAMP WITH TIME ZONE
.
Отправка.
Instant instant = Instant.now() ; // Capture the current moment in UTC.
myPreparedStatement.setObject( … , instant ) ;
Получение.
Instant instant = myResultSet.getObject( … , Instant.class );
Вы можете настроить UTC для определенного часового пояса.
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
Если вы работали в своей бизнес-логике с объектом OffsetDateTime
или ZonedDateTime
, извлеките Instant
, вызвав их метод toInstant
.
Instant instant = myZonedDateTime.toInstant() ; // Extract an `Instant` object, effectively adjusting from some particular time zone to UTC.
незональный
Совершенно другой вид даты-времени - это тот, у которого намеренно отсутствует какая-либо концепция часового пояса или смещения от UTC. Таким образом, этот тип не представляет конкретный момент, является не точкой на временной шкале. Этот тип представляет потенциальных моментов в диапазоне около 26-27 часов (диапазон различных часовых поясов).
Для этого типа даты и времени:
- В Java используйте
LocalDateTime
class.
- В Postgres используйте тип
TIMESTAMP WITHOUT TIME ZONE
.
Когда входные данные отправляются в столбец этого типа в Postgres, любая сопровождающая информация о зоне / смещении игнорируется. Дата и время суток принимаются как есть и сохраняются непосредственно в базе данных. При получении вы получаете ту же дату и время суток, без настройки на какой-либо конкретный часовой пояс.
О 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?
Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является полигоном для возможных будущих дополнений к java.time. Здесь вы можете найти несколько полезных классов, таких как Interval
, YearWeek
, YearQuarter
и more .