Представление будущего времени в PostgreSQL - PullRequest
0 голосов
/ 27 февраля 2019

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

Postgres имеет timestamp with timezone, но под прикрытием он сохраняет его как UTC, делая вывод, что указанный часовой пояс является смещением UTC.Если правила часового пояса будут изменены, это не будет отражено в столбце.

Что рекомендуется в этом случае?

Ответы [ 3 ]

0 голосов
/ 27 февраля 2019

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

Это кажется отсталым.Основное преимущество UTC над другими часовыми поясами состоит в том, что он меньше подвержен неожиданным будущим изменениям: UTC вводит только високосные секунды в известных ограниченных точках календарного года;и не имеет ни одного из частых политически обязательных изменений смещения.

Хранение значений в некотором локально управляемом часовом поясе оставляет эти значения более склонными (по сравнению с UTC) к произвольным, непредсказуемым будущим изменениям значения.

Итак, общая рекомендация: хранить все значения времени (будь то дата или дата + время) как UTC в базе данных, обрабатывать их внутренне как значения UTC;и преобразовывать в / из локального часового пояса только на внешних интерфейсах.

Для PostgreSQL это означает, что предпочитают TIMESTAMP WITH TIME ZONE.

0 голосов
/ 27 февраля 2019

Думайте [об этом] как событие календаря.UTC для этого не имеет смысла

Похоже, вы хотите сохранить местное время относительно определенного часового пояса.В этом случае сохраните timestamp (без часового пояса) и timezone в отдельном столбце.

Например, предположим, вы хотите записать событие, которое произойдет в 10 часов утра 26 февраля 2030 года.в Чикаго, и это должно быть в 10:00 по местному времени независимо от правила часового пояса, действующего на эту дату.

Если база данных хранит метку времени без часового пояса:

unutbu=# select '2030-02-26 10:00:00'::timestamp as localtime, 'America/Chicago' AS tzone;
+---------------------+-----------------+
|      localtime      |      tzone      |
+---------------------+-----------------+
| 2030-02-26 10:00:00 | America/Chicago |
+---------------------+-----------------+

Позже вы можете найти дату и время UTC для события, используя

unutbu=# select '2030-02-26 10:00:00'::timestamp AT TIME ZONE 'America/Chicago' AT TIME ZONE 'UTC';
+---------------------+
|      timezone       |
+---------------------+
| 2030-02-26 16:00:00 |
+---------------------+

Запрос возвращает дату и время UTC, 2030-02-26 16:00:00, что соответствует 2030-02-26 10:00:00 местному времени в Чикаго.

Использование AT TIME ZONE задерживает применение правил часового пояса до момента выполнения запроса вместо вставки timestamptz.


Использование AT TIME ZONE в timestamp локализует дату и время в указанном часовом поясе, но сообщает дату и время в часовом поясе пользователя .Использование AT TIME ZONE для timestamptz преобразует дату и время в заданный часовой пояс, а затем сбрасывает смещение, возвращая, таким образом, timestamp.Выше AT TIME ZONE используется дважды: сначала для локализации timestamp, а затем для преобразования возвращенного timestamptz в новый часовой пояс (UTC).Результат - timestamp в UTC.

Вот пример, демонстрирующий поведение AT TIME ZONE на timestamp с:

unutbu=# SET timezone = 'America/Chicago';
unutbu=# SELECT '2030-02-26 10:00:00'::timestamp AT TIME ZONE 'America/Chicago';
+------------------------+
|        timezone        |
+------------------------+
| 2030-02-26 10:00:00-06 |
+------------------------+

unutbu=# SET timezone = 'America/Los_Angeles';
unutbu=# SELECT '2030-02-26 10:00:00'::timestamp AT TIME ZONE 'America/Chicago';
+------------------------+
|        timezone        |
+------------------------+
| 2030-02-26 08:00:00-08 |
+------------------------+

2030-02-26 10:00:00-06 и 2030-02-26 08:00:00-08являются одинаковыми датами, но сообщаются в разных часовых поясах пользователя.Это показывает, что 10:00 в Чикаго - это 8:00 в Лос-Анджелесе (с использованием текущих определений часовых поясов):

unutbu=# SELECT '2030-02-26 10:00:00-06'::timestamptz AT TIME ZONE 'America/Los_Angeles';
+---------------------+
|      timezone       |
+---------------------+
| 2030-02-26 08:00:00 |
+---------------------+

Альтернативой двойному использованию AT TIME ZONE является установка часового пояса пользователя вUTC.Тогда вы могли бы использовать

select localtime AT TIME ZONE tzone

Обратите внимание, что когда это сделано таким образом, вместо timestamp возвращается timestamptz.


Остерегайтесь, что хранение локальных времен может быть проблематичным, потому чтомогут быть несуществующие времена и неоднозначные времена.Например, 2018-03-11 02:30:00 - это несуществующее местное время в America/Chicago.Postgresql нормализует несуществующее местное время, предполагая, что оно относится к соответствующему времени после начала перехода на летнее время (DST) (как будто кто-то забыл перевести свои часы вперед):

unutbu=# select '2018-03-11 02:30:00'::timestamp AT TIME ZONE 'America/Chicago' AT TIME ZONE 'UTC';
+---------------------+
|      timezone       |
+---------------------+
| 2018-03-11 08:30:00 |
+---------------------+
(1 row)

unutbu=# select '2018-03-11 03:30:00'::timestamp AT TIME ZONE 'America/Chicago' AT TIME ZONE 'UTC';
+---------------------+
|      timezone       |
+---------------------+
| 2018-03-11 08:30:00 |
+---------------------+
(1 row)

Примером неоднозначного местного времени является 2018-11-04 01:00:00 в America/Chicago.Это происходит дважды из-за летнего времени.Postgresql разрешает эту неоднозначность, выбирая более позднее время после окончания летнего времени:

unutbu=# select '2018-11-04 01:00:00'::timestamp AT TIME ZONE 'America/Chicago' AT TIME ZONE 'UTC';
+---------------------+
|      timezone       |
+---------------------+
| 2018-11-04 07:00:00 |
+---------------------+

Обратите внимание, что это означает, что нет никакого способа сослаться на 2018-11-04 06:00:00 UTC, сохраняя местное время в часовом поясе America/Chicago:

unutbu=# select '2018-11-04 00:59:59'::timestamp AT TIME ZONE 'America/Chicago' AT TIME ZONE 'UTC';
+---------------------+
|      timezone       |
+---------------------+
| 2018-11-04 05:59:59 |
+---------------------+
0 голосов
/ 27 февраля 2019

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

PostgreSQL внутренне хранит количество микросекунд с 2000-01-01 00:0000, что безопасно от изменения часового пояса.Если вы продолжаете обновлять свой PostgreSQL, он всегда будет правильно отображать это абсолютное значение для вашего часового пояса сеанса.

В PostgreSQL нет положений о дополнительных секундах.

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