Хранение часовой зоны в бд

Подскажите пожалуйста как добавить поле в сущности типа дата при сохранении которого в бд будет записываться время и часовая зона?

Еще хочу добавить что мы пытались создать сущность в которой добавили поле типа OffsetDateTime и в БД postgres оно создается как timestamp with timezone то есть тип поля правильный. Но при записи данных в бд часовая зона теряется, время преобразовывается к текущей зоне на сервере. В БД попадает запись 2020-08-05 10:47:51 а должно быть 2020-08-05 10:47:51+0008

Здравствуйте,
Насколько помню ORM (в частности EclipseLink всегда сохраняет время в таймзоне сервера). Но при этом должны корректно выполняться временные преобразования: то есть если мы указали дата и время в одной таймзоне, то оно должно преобразоваться в корректные дата и время в серверной таймзоне.

Касательно таймзон: если на пользователе возможно сконфигурировать его таймзону, то в этом случае компоненты в UI для ввода даты, которые привязаны к полям сущности будут использовать таимзоны. То есть в UI будет отображаться дата соответствующая таймзоне пользователя.
Немного про таймзоны описано здесь: https://doc.cuba-platform.com/manual-7.2/timeZone.html и https://doc.cuba-platform.com/manual-7.2/gui_DateField.html

DateField can perform timestamp value conversions between server and user time zones if the user’s time zone is set by setTimeZone() method. The time zone is assigned automatically from the current user session when the component is bound to an entity attribute of the timestamp type. If the component is not bound to such attribute, you can call setTimeZone() in the screen controller to make the DateField perform required conversions.

Тогда подскажите пожалуйста как решить задачу? Нам необходимо хранить дату в БД + часовой пояс

Добрый день,

Объясните поподробнее, что значит “+ часовой пояс”?

Объясню, на примере - тип “timestamp with time zone” в PostgreSQL не хранит часовой пояс.
Этот тип данных просто сохраняет дату как момент в абсолютном времени и потом выдает эту дату SQL-клиентам, форматируя ее по-разному в зависимости от их часового пояса (настройки сессии timezone).

Смотрите:

create table my_event (
	id serial, 
	ts timestamp with time zone, 
	primary key (id)
);

insert into my_event (ts) values ('2020-08-07 11:03+06');

show timezone;
> "Europe/Samara"

select * from my_event;
> 1	"2020-08-07 09:03:00+04"

set timezone to 'Europe/Paris';
> SET

select * from my_event;
1	"2020-08-07 07:03:00+02"

Даты “2020-08-07 09:03:00+04” и “2020-08-07 07:03:00+02” для типа “timestamp with time zone” одинаковы.

При этом параметр сессии “timezone” берется из Java system property -Duser.timezone, т.е. он всегда одинаков для запущенного приложения, если его явно не проставлять sql-скриптом в транзакции.

Если вам нужно именно хранить исходный часовой пояс, в котором произошло событие и который отличался от серверного ("+06"), то придется для этого заводить отдельную колонку в БД.

1 симпатия
  • часовой пояс значит:

Когда вы смотрите в таблицу sql то после с датой хранит часовой пояс пример: 2020-08-07 07:03:00+02

Postgres 100% позволяет нам сохранять дату вместе с часовым поясом и для этого нет необходимости создавать отдельное поле. То есть получается что вы рекомендуете вместо одного поля создать два?

Алексей, вы прочитали и поняли полностью мой пост?

Если не поняли, то что непонятно?
Поэкспериментируйте сами с SQL консолью и Postgres.
Попробуйте вставить дату с тайм-зоной, отличающейся от вашей (например 2020-08-07 07:03:00+08)

У нас задача в том, чтобы посчитать аналитику по событиям. При этом приложение одно, а события происходят в разных временных зонах. Задача немного упрощается тем, что аналитика считается всегда в рамках одного региона, а значит одной временной зоны. Но в целом регионов несколько, и выставить “-Duser.timezone” для всего приложения - не корректно.

В общем нам нужно каким-то образом задавать таймзону для каждого отдельного запроса. Документация https://postgrespro.ru/docs/postgrespro/9.5/functions-datetime описывает как это сделать в чистом SQL -

SELECT TIMESTAMP '2001-02-16 20:38:40' AT TIME ZONE 'America/Denver';

Как это лучше сделать в рамках методов Cuba?

Вопрос в том как аналитика рассчитывается. В случае если обработка дат выполняется на уровне sql (например группировка по начале дня/недели в текущей таймозоне), то и преобразование между таймзонами необходимо делать на уровне sql.

В случае Java кода есть ZonedDateTime, OffsetDateTime, старый Calendar - где возможно обеспечить работу с таймзонами.

Дата что в sql, что java.util.Date - это точка на числовой оси (хранится в UTC) и она может соотноситься одновременно с датой и временем в разных числовых таймзонах. Всегда можно преобразовать из одной таймзоны в другую.

В продолжение хочу сказать, что OffsetDateTime в связке с timestamp with time zone хранит в себе не таймзону, а смещение по UTC (то есть не учитывает переводы на зимнее/летнее время).

Кейс с таймзоной на уровне Java мог бы покрыть ZonedDateTime, но он не поддерживается стандартом JPA.

Единственный кейс рабочий который мне видится работать с java.util.Date + timestamp with time zone и делать преобразования между таймзонами на уровне БД или приложения.