Значения меток времени хранятся по-разному в PostgreSQL, когда тип данных отличается WITH TIME ZONE
от WITHOUT TIME ZONE
? Можно ли проиллюстрировать различия с помощью простых тестовых случаев?
postgresql
types
timestamp
timezone
Larsenal
источник
источник
Ответы:
Различия описаны в документации PostgreSQL для типов даты / времени . Да, лечение
TIME
илиTIMESTAMP
отличается от одногоWITH TIME ZONE
илиWITHOUT TIME ZONE
. Это не влияет на то, как хранятся значения; это влияет на то, как они интерпретируются.Влияние часовых поясов на эти типы данных подробно описано в документации. Разница возникает из того, что система может разумно знать о значении:
С часовым поясом как частью значения, значение может быть отображено как локальное время в клиенте.
Без часового пояса как части значения очевидным часовым поясом по умолчанию является UTC, поэтому он отображается для этого часового пояса.
Поведение отличается в зависимости как минимум от трех факторов:
WITH TIME ZONE
ИлиWITHOUT TIME ZONE
) значения.Вот примеры, охватывающие комбинации этих факторов:
источник
timestamp with time zone
аtimestamp without time zone
в Postgres * на самом деле не хранят информацию о часовом поясе. Вы можете подтвердить это, заглянув на страницу документа с типом данных: оба типа занимают одинаковое количество октетов и имеют диапазон значений сохранения, поэтому нет места для хранения информации о часовом поясе. Текст страницы подтверждает это. Что-то неправильно: «без tz» означает «игнорировать смещение при вставке данных», а «с tz» означает «использовать смещение для настройки на UTC».Я пытаюсь объяснить это более понятно, чем упомянутая документация PostgreSQL.
Ни один из
TIMESTAMP
вариантов не хранит часовой пояс (или смещение), несмотря на то, что предлагают названия. Разница заключается в интерпретации хранимых данных (и в предполагаемом приложении), а не в самом формате хранения:TIMESTAMP WITHOUT TIME ZONE
хранит местное время и дату (ака. дата и время настенного календаря). PostgreSQL может определить его часовой пояс, хотя ваше приложение может знать, что это такое. Следовательно, PostgreSQL не выполняет преобразование, связанное с часовым поясом, при вводе или выводе. Если значение было введено в базу данных как'2011-07-01 06:30:30'
, то не важно, в каком часовом поясе вы его отобразите позже, оно по-прежнему будет содержать год 2011, месяц 07, день 01, 06 часов, 30 минут и 30 секунд (в некотором формате). Кроме того , любое смещение или часовой пояс указывается на входе игнорируется PostgreSQL, так'2011-07-01 06:30:30+00'
и'2011-07-01 06:30:30+05'
такие же , как только'2011-07-01 06:30:30'
. Для разработчиков Java: это аналогjava.time.LocalDateTime
.TIMESTAMP WITH TIME ZONE
сохраняет точку на временной шкале UTC. Как это выглядит (сколько часов, минут и т. Д.) Зависит от вашего часового пояса, но всегда относится к одному и тому же «физическому» моменту (например, моменту реального физического события). Входные данные внутренне преобразуются в UTC, и именно так они сохраняются. Для этого смещение ввода должно быть известно, поэтому, когда на входе нет явного смещения или часового пояса (например'2011-07-01 06:30:30'
), предполагается, что он находится в текущем часовом поясе сеанса PostgreSQL, в противном случае используется явно указанное смещение или часовой пояс. (как в'2011-07-01 06:30:30+05'
). Выходные данные отображаются в преобразованном в текущий часовой пояс сеанса PostgreSQL. Для разработчиков Java: это аналогjava.time.Instant
(с более низким разрешением), но с JDBC и JPA 2.2 вы должны отобразить его наjava.time.OffsetDateTime
(или наjava.util.Date
илиjava.sql.Timestamp
конечно).Некоторые говорят, что оба
TIMESTAMP
варианта хранят дату и время UTC. Вроде, но, по моему мнению, это сбивает с толку.TIMESTAMP WITHOUT TIME ZONE
хранится как aTIMESTAMP WITH TIME ZONE
, который отображается с часовым поясом UTC и дает тот же год, месяц, день, часы, минуты, секунды и микросекунды, что и в местной дате-времени. Но он не предназначен для представления точки на временной шкале, которую говорит интерпретация UTC, это просто способ кодирования локальных полей даты и времени. (Это некоторая группа точек на временной шкале, поскольку реальный часовой пояс не является UTC; мы не знаем, что это такое.)источник
TIMESTAMP WITH TIME ZONE
какInstant
. Оба представляют точку на временной шкале в UTC.Instant
на мой взгляд, предпочтительнее, такOffsetDateTime
как он более самодокументируемый: ATIMESTAMP WITH TIME ZONE
всегда извлекается из базы данных как UTC, аInstant
всегда находится в UTC, так что естественное совпадение, тогда какOffsetDateTime
может нести другие смещения.OffsetDateTime
как сопоставленный тип Java. Я не уверен, еслиInstance
все еще неофициально поддерживается где-то.'2011-07-01 06:30:30+00'
и'2011-07-01 06:30:30+05'
игнорируется, но я могу это сделать,insert into test_table (date) values ('2018-03-24T00:00:00-05:00'::timestamptz);
и оно будет правильно преобразовывать его в utc. где дата является меткой времени без часового пояса. Я пытаюсь понять, какова основная ценность метки времени с часовым поясом и возникают проблемы.::timestamptz
. При этом вы преобразуете строку вTIMESTAMP WITH TIME ZONE
, и когда она будет дополнительно преобразована вWITHOUT TIME ZONE
, в ней будут храниться день «настенного календаря» и время настенного времени этого момента, как видно из вашего часового пояса сеанса (который может быть UTC). Это будет только локальная временная метка с неопределенным смещением (без зоны).Вот пример, который должен помочь. Если у вас есть временная метка с часовым поясом, вы можете преобразовать ее в любой другой часовой пояс. Если у вас нет базового часового пояса, он не будет правильно преобразован.
Вывод:
источник
timestamp
иtimestamptz
значит.timestamptz
означает абсолютный момент времени (UTC), тогда какtimestamp
обозначает то, что часы показывали в определенном часовом поясе. Таким образом, при переходеtimestamptz
на часовой пояс вы спрашиваете, что часы показывали в Нью-Йорке в этот абсолютный момент времени? тогда как при «преобразовании» atimestamp
вы спрашиваете, какой был абсолютный момент времени, когда часы в Нью-Йорке показывали x?AT TIME ZONE
Конструкция является мозг тизера самостоятельно, даже если вы уже понимаетеWITH
vs.WITHOUT TIME ZONE
типы. Так что это любопытный выбор для их объяснения. (: (AT TIME ZONE
преобразуетWITH TIME ZONE
метку времени вWITHOUT TIME ZONE
метку времени, и наоборот ... не совсем очевидно.)now()::timestamp AT TIME ZONE 'CST'
не имеет смысла, если вы не знаете, в какой момент часы для зоны 'CST' будут показывать время, которое показывают ваши локальные часы