Сохранять часовой пояс в типе timestamptz PostgreSQL
В соответствии со стандартом ISO8601 datetime
2004-10-19 10:23:54+02
Возможно ли иметь это значение с смещением +02
, отраженным в сохраненном значении столбца, а также сохраненным при его выборе?
Из моего чтения соответствующего раздела документов. Поведение Postgres по умолчанию - это преобразование в UTC, в котором исходное смещение теряется. Это, безусловно, то, что я вижу.
Доступ к данным осуществляется через ORM, который не может добавить какое-либо специальное преобразование tz, поэтому мне действительно нужно просто сохранить дату-время с исходным смещением и отобразить значение, когда оно выбрано.
Для тех, кто умирает, чтобы сказать мне тот же самый экземпляр во времени, сохранение этого значения имеет значение для этих данных.
Ответы
Ответ 1
Как вы уже выяснили, часовой пояс вообще не сохраняется с типами даты/времени Postgres, даже с timestamptz
. Его роль - это только модификатор ввода или декодер вывода, соответственно. Сохраняется только значение (момент времени). Достаточно подробные сведения в этом ответном ответе:
Поэтому, если вы хотите сохранить эту часть входной строки, вам нужно извлечь ее из строки и сохранить ее самостоятельно. Я бы использовал таблицу типа:
CREATE TABLE tstz
...
, ts timestamp -- without time zone
, tz text
)
tz
, будучи text
, может содержать числовое смещение, а также временную зону аббревиатура или часовой пояс имя.
Трудность состоит в том, чтобы извлечь часть часового пояса в соответствии со всеми различными правилами, которые выполняет парсер, и таким образом, что это не будет легко ломаться. Вместо того, чтобы приготовить свою собственную процедуру, заставить парсер выполнять работу. Рассмотрим эту демонстрацию:
WITH ts_literals (tstz) AS (
VALUES ('2013-11-28 23:09:11.761166+03'::text)
,('2013-11-28 23:09:11.761166 CET')
,('2013-11-28 23:09:11.761166 America/New_York')
)
SELECT tstz
,tstz::timestamp AS ts
,right(tstz, -1 * length(tstz::timestamp::text)) AS tz
FROM ts_literals;
SQL Fiddle.
Работает с или без T
между датой и временем. Ключевая логика здесь:
right(tstz, -1 * length(tstz::timestamp::text)) AS tz
Возьмите то, что осталось от строки timestamp после обрезки длины того, что парсер определил как компонент даты/времени. Это зависит от ввода, как вы заявили:
проверенные строки ISO8601
Ответ 2
Java-разработчики могут использовать Joda Time в сочетании с Jadira UserType PersistentDateTimeAndZone
. Пример:
@Basic(optional = false)
@Columns(columns = { @Column(name = "modificationtime"),
@Column(name = "modificationtime_zone") })
@Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTimeAndZone")
@Index(name = "payment_modificationtime_idx")
private DateTime modificationTime = null;
В этом примере информация DateTime
находится в двух столбцах:
-
modificationtime timestamp without time zone
для сохранения метки времени в часовом поясе UTC
-
modificationtime_zone varchar(255)
, чтобы сохранить идентификатор часового пояса в виде строки (например, America/Caracas
)
Хотя Joda Time и Jadira (и Hibernate) специфичны для Java (и это де-факто подход), вышеупомянутый подход к структурированию столбцов RDBMS для хранения как временной метки, так и часового пояса может применяться к любому языку программирования.
Ответ 3
Родные postgres типы данных даты/времени не будут сохранять ваш часовой пояс для вас. Если вам нужно как запросить его как временную метку в базе данных, так и представить исходную информацию, вам придется каким-то образом хранить обе части.
Я собирался предложить, чтобы ваш ORM мог определить пользовательские методы надувания/дефляции для обработки магии, но, по-видимому, этого не может. Вы должны указать, какую ОРМ вы используете.
У вас может быть хранилище ORR/получить строку в базе данных и использовать trigger в Postgres, чтобы преобразовать это в хранимый timestamptz в другом столбце, который используется при выполнении запросов на стороне базы данных. Если у вас много таблиц с данным типом данных, это может быть немного громоздким.
Если вам действительно нужны данные в одном столбце в базе данных, вы можете определить составной тип в Postgres, хотя ваш ORM не может быть в состоянии справиться с ними.