2013-11-28 5 views
13

Для ISO8601 совместимого DateTimeсохранить часовой пояс в PostgreSQL timestamptz типа

2004-10-19 10:23:54+02 

Можно ли иметь это значение, с +02 смещения, отраженным в хранимом значении столбца, а также сохраняется, когда он выбран?

Из-за моего чтения appropriate section of the docs Поведение Postgres по умолчанию - это конвертировать в UTC, в котором исходное смещение теряется. Это, безусловно, то, что я вижу.

Доступ к данным осуществляется через ORM, который не может добавить никакого специального преобразования tz, поэтому мне действительно нужно просто сохранить дату-время с исходным смещением и отобразить значение, когда оно выбрано.

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

+0

Возможно ли сохранить смещение в отдельной колонке, чтобы вы не были в помине Postgres? – tadman

+1

@tadman Ha. Попытка перевернуть это в одну колонку. Кажется, это не похоже на необоснованную вещь. – markdsievers

+0

Что такое источник данных? Строковый литерал? Или другой столбец - какого типа? –

ответ

13

Как вы уже выяснили себя, часовой пояс не сохраняются на все с датой 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 

Возьмите то, что осталось от строки метки времени после обрезки длины Разборщик определены как дата/время компонента. Это зависит от входного того, как вы заявили:

валидированных ISO8601 строки

+2

Спасибо за подробный ответ. Поэтому разочарование в одном столбце невозможно. – markdsievers

+3

@markdsievers Если вы думаете об этом, то смещение является излишней информацией. «Реальное» время - UTC/GMT, количество миллисекунд с эпохи. Если в контексте вашего приложения и данных вы действительно заботитесь о сохранении смещения, это означает, что вы заботитесь о местном времени, а это означает, что вы должны захватывать и записывать часовой пояс. Пример: «Тихий океан/Окленд». Часовой пояс больше, чем смещение, он включает в себя правила/историю для летнего времени (DST) и другие аномалии. Без учета часового пояса в UTC нет никакого полезного различия между датой-временем + смещением и датой-временем. –

1

Родные postgres date/time datatypes не собираются сохранять ваш часовой пояс для вас. Если вам нужно как запросить его как временную метку в базе данных и представить исходную информацию, вам придется хранить обе части информации в некотором роде.

Я собирался предложить вашему ORM, чтобы определить пользовательские методы надувания/спускания, чтобы справиться с магией, но, по-видимому, это невозможно. Вы должны указать, какую ОРМ вы используете.

Возможно, у вас есть ORM store/retrieve строка в базе данных и используйте trigger в Postgres, чтобы преобразовать его в timestamptz, хранящийся в другом столбце, который используется при выполнении запросов на стороне базы данных. Если у вас много таблиц с данным типом данных, это может быть немного громоздким.

Если вы действительно хотите данные в одном столбце базы данных, вы можете определить composite type в Postgres, хотя ваш ORM, возможно, не сможет справиться с ними.

+0

Умышленно не указаны данные ORM поскольку это является предметом другого последующего вопроса. Этот вопрос просто рассматривает возможность хранения TZ в одном столбце типа timestamptz Postgres, как видно из названия. – markdsievers

2

Java разработчики могут использовать Joda Time в сочетании с Jadira UserType «s 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 информации находится в 2-х столбцах:

  1. modificationtime timestamp without time zone для хранения метки времени в часовом поясе UTC
  2. modificationtime_zone varchar(255) для хранения часового пояса ID в виде строки (например, America/Caracas)

Хотя Joda Time и Jadira (и Hibernate) специфичны для Java (и являются de facto), вышеупомянутый подход к структурированию столбцов РСУБД для хранения как временной метки, так и часового пояса может применяться к любому языку программирования.

Смежные вопросы