Каков действительный вариант использования TIMESTAMP без TIME ZONE?

41

Существует длинный и довольно разъясняющий ответ о различиях между

  • TIMESTAMP WITH TIME ZONE vs-
  • TIMESTAMP WITHOUT TIME ZONE

доступны в этом посте . То, что я хотел бы знать: есть ли действительные варианты использования для фактического использования, TIMESTAMP WITHOUT TIME ZONEили это следует рассматривать как анти-паттерн.

Маркус Юний Брут
источник
Этот вопрос рискует быть закрытым, будучи «главным образом основанным на мнении». Я попытался дать некоторые объективные взгляды в своем ответе ниже.
Colin 't Hart
2
Эта проблема вполне реальна, каждый тип данных имеет разное значение. Поэтому я бы не стал рассматривать этот Вопрос как основанный на мнении.
Василий Бурк

Ответы:

30

Об этом говорится во многих местах, но я думаю , что стоит отметить , всегда , когда мы сравним timestamp with time zoneс timestamp without time zoneтипами: не хранит часовой пояс информацию вместе с меткой времени . Что он делает, чтобы хранить все данные в часовом поясе UTC, как указано в документации :timestamp WITH time zone

Для метки времени с часовым поясом внутренне сохраненное значение всегда указывается в формате UTC (универсальное координированное время, традиционно известное как среднее время по Гринвичу, GMT). Входное значение с указанным явным часовым поясом преобразуется в UTC с использованием соответствующего смещения для этого часового пояса. Если во входной строке не указан часовой пояс, предполагается, что он находится в часовом поясе, указанном системным параметром TimeZone, и преобразуется в UTC с использованием смещения для часового пояса.

Для некоторых считается допустимым использование timestamp WITHOUT time zoneв ситуациях, когда (1) все находится в одном часовом поясе или (2) прикладной уровень обрабатывает часовой пояс и просто хранит все в определенном часовом поясе (обычно UTC). Но это также считается анти-паттерном, простым, потому что правильное решение для (1) состоит в том, чтобы настроить параметр TimeZone для данного единого часового пояса для системы, и (2) уже решен, поскольку PostgreSQL уже хранит все в одном часовом поясе. (УНИВЕРСАЛЬНОЕ ГЛОБАЛЬНОЕ ВРЕМЯ).

Теперь, с этими двумя, у меня может быть только одна веская причина timestamp WITHOUT time zone. Это когда вы хотите сохранить события в будущем, и когда мы дойдем до этого времени, должно быть запущено какое-то предупреждение. Это может быть полезно, timestamp WITH time zoneесли и только если правила, определенные законами региона о часовом поясе, никогда не менялись. Наиболее распространенное правило, которое изменяется, касается принятия или не перехода на летнее время (DST).

Например, представьте, что вы, скажем, 2013-06-15(еще не в летнее время) запланировали какое-то событие, 2013-01-15 10:00которое должно было произойти (которое уже было бы в летнее время), и в 2013-06-15вашем регионе было назначено принять летнее время; но через некоторое время после этого правительство изменило правило и заявило, что ваш регион больше не будет использовать DST, и внезапно ваше запланированное время станет 2013-01-15 11:00(а не 10:00), что если вы используете timestamp WITH time zoneи будете поддерживать свои конфигурации TZ в актуальном состоянии. Конечно, вы также можете заметить, что такие случаи можно обрабатывать и с часовым поясом, если вы отслеживаете изменения правил в интересующих вас регионах / часовых поясах и обновляете затронутые записи.

Стоит отметить, что некоторые регионы часто меняют эти правила (как, например, в Бразилии, некоторые штаты - не вся страна - часто меняются), но в большинстве случаев это меняет это очень рано, поэтому на ваших пользователей будут влиять только события, запланированные очень далеко от текущее время

После всего сказанного у меня есть только одно предложение. Если у вас есть пользователи, журналы или что-то в разных часовых поясах, сохраните часовой пояс, откуда они поступают, выберите и используйте timestamp with time zone. Таким образом, вы можете (1) пересекать события, происходящие ближе друг к другу для разных источников (независимо от их часовых поясов) и (2) показывать исходное время (время часов), когда событие произошло.

MatheusOl
источник
Вы говорите: «У меня может быть только одна веская причина использовать временную метку с часовым поясом». Если это не опечатка, то действительно ли вы предполагаете, что «метка времени без часового пояса» на самом деле более уместна / менее подвержена недоразумениям, чем «метка времени с часовым поясом»? Это кажется мне нелогичным.
Маркус Юниус Брутус
@MarcusJuniusBrutus, извините за это, это была действительно опечатка, и я думал наоборот ... Проверьте отредактированный ответ.
MatheusOl
codeblog.jonskeet.uk/2019/03/27/… подробно обсуждает этот сценарий будущих правил событий, которые могут измениться (с тем же выводом)
Бени Чернявский-Паскин
19

Да. Есть варианты использования для TIMESTAMP WITHOUT TIME ZONE.

  • В обычных бизнес-приложениях этот тип будет использоваться только для:
    • Бронирование будущих встреч
    • Представление одного и того же времени суток в разных часовых поясах, например, в полдень 23-го числа в Токио и в Париже (два разных момента между часами, в одно и то же время суток)
  • Для отслеживания моментов, определенных точек на временной шкале, всегда используйте TIMESTAMP WITH TIME ZONE, а не WITHOUT.

TIMESTAMP WITHOUT TIME ZONEзначения не являются точкой на временной шкале, а не фактическими моментами. Они представляют приблизительное представление о потенциальных моментах, возможных точках на временной шкале в диапазоне около 26-27 часов (диапазон часовых поясов вокруг земного шара). Они не имеют реального смысла, пока вы не примените часовой пояс или смещение от UTC .

Пример: Рождество

Например, скажем, вам нужно записать начало праздников / праздников.

Table: holiday_

Column: year_         Type: SMALLINT
Column: description_  Type: VARCHAR
Column: start_        Type: TIMESTAMP WITHOUT TIME ZONE

Чтобы зафиксировать тот факт, что Рождество начинается после полуночи 25 декабря этого года, мы должны сказать, 2016-12-25 00:00:00 без какого-либо часового пояса. В начале дня Санты он посещает Окленд в Новой Зеландии сразу после полуночи, так как это одна из самых ранних ночей в мире. Затем он направляется на запад, как и в следующую полночь, вскоре достигнув Филиппин. Затем олени двигаются в западном направлении, достигая Индии в полночь, что происходит через несколько часов после этой полуночи в Окленде. Намного позже все еще полночь в Париже FR, и еще позже полночь в Монреале, Калифорния. Все эти посещения Санта-Клауса происходят в разные моменты времени , но все они происходили вскоре после полуночи, в каждую полночь каждого населенного пункта.

Поэтому запись 2016-12-25 00:00:00без какого-либо часового пояса, как начало Рождества, является информативной и законной, но только смутно. Пока вы не скажете «Рождество в Окленде» или «Рождество в Монреале», у нас нет определенного момента времени. Если вы записываете фактический момент каждый раз, когда сани приземляются, вы должны использовать, TIMESTAMP WITH TIME ZONEа не WITHOUTтип.

Похоже на Рождество в канун Нового года. Когда нью-йоркский бал Таймс-сквер падает , люди в Сиэтле все еще пьют шампанское и готовят рога для вечеринки . И все же мы записали бы идею новогоднего момента как 2017-01-01 00:00:00в TIMESTAMP WITHOUT TIME ZONE. Напротив, если мы хотим записать, когда мяч упал в Нью-Йорке или когда люди в Сиэтле взорвали свои рога, мы бы вместо этого использовалиTIMESTAMP WITH TIME ZONE (не WITHOUT), чтобы записать эти реальные моменты, каждые три часа друг от друга.

Пример: заводские смены

Другим примером может быть запись политики, которая включает настенное время в разных местах. Скажем, у нас есть заводы в Детройте, Дюссельдорфе и Дели. Если мы скажем, что на всех трех фабриках первая смена начинается в 6 утра с перерыва на обед в 11:30, это можно записать какTIMESTAMP WITHOUT TIME ZONE . Опять же, эта информация полезна неопределенным образом, но не указывает конкретный момент времени, пока мы не применим часовой пояс. Новый день наступает раньше на востоке. Таким образом, фабрика в Дели будет открыта первой в 6 часов утра. Через несколько часов фабрика в Дюссельдорфе начинает работу в 6 часов утра. Но фабрика в Детройте на самом деле не откроется еще через шесть часов, когда наступит ее 6 утра.

Сравните эту идею (о том, когда обычно начинается заводская смена) с историческим фактом, когда каждый заводской рабочий начал свою смену в определенный день. Часы - это реальный момент, фактическая точка на временной шкале. Таким образом, мы записали бы это в столбце типа, TIMESTAMP WITH TIME ZONEа неWITHOUT типа.

Так что да, есть законные варианты использования для TIMESTAMP WITHOUT TIME ZONE. Но по моему опыту с бизнес-приложениями, они относительно редки. В бизнесе мы склонны заботиться о реальных моментах: когда фактический счет-фактура поступил, когда именно этот контракт вступил в силу, в какой момент была выполнена эта банковская транзакция. Поэтому в таких распространенных ситуациях нам нужен TIMESTAMP WITH TIME ZONEтип.

Для получения дополнительной информации см. Мой ответ на аналогичный вопрос. Должен ли я хранить метки времени UTC или местное время для смен?

Postgres

Обратите внимание, что Postgres специально никогда не сохраняет информацию о часовом поясе, указанную при вставке временной метки.

  • TIMESTAMP WITH TIME ZONE
    • Любой указанный часовой пояс или смещение, включенное во входные данные, используется для настройки значения на UTC и сохраняется. Переданная информация о зоне / смещении затем отбрасывается. Подумай TIMESTAMP WITH TIME ZONEкак TIMESTAMP WITH RESPECT FOR TIME ZONE.
    • Вводимое в 12:00 полдень 7 марта этого года в Индии время суток будет скорректировано на UTC путем вычитания пяти с половиной часов: 6:30 утра.
  • TIMESTAMP WITHOUT TIME ZONE
    • Любой указанный часовой пояс или смещение, включенное во входные данные, полностью игнорируется.
    • Ввод 12:00 в полдень 7 марта этого года в Индии записывается как 12:00 7 марта этого года без корректировки.

Стандарт SQL практически не затрагивает вопросы типов данных и поведения даты и времени. Таким образом, база данных широко варьируется в обработке даты и времени.

Базилик Бурк
источник
кроме того, с заводскими (или больничными) сменами, каждый, кто работает в смену на кладбище в дни перехода на летнее время, будет неправильно записывать свои часы, записанные без часового пояса.
Jasen
Я думаю, что в последнем примере есть опечатка: «Ввод 12:00 в полдень 7 марта ... должен быть« записан как 12 : 00 »(не 21:00)
TmTron
11

Я хотел бы добавить к этому еще одно мнение, которое противоречит большей части того, что было написано в других ответах. На мой взгляд, timestamp with time zoneесть очень мало действительных вариантов использования, и timestamp without time zoneв целом должно быть предпочтительным.

Во-первых, вы должны понимать шаблон «UTC везде», который обычно рекомендуется для всех приложений, которые не предъявляют особых требований. Это просто означает, что ваше приложение должно представлять все свои метки времени в UTC, везде и всегда. Конечно, вы будете показывать локальную дату / время пользователям, но идея заключается в том, чтобы преобразовать их на самом краю вашей программы при рендеринге представления. Это правильное место для объединения временной метки UTC (которую вы, возможно, загрузили из базы данных) и временной зоны пользователя (которая может быть получена из браузера) в локальную временную метку.

Если вы следуете этому шаблону, тогда timestamp with time zoneэто анти-шаблон. Все, что делает этот тип, - это заставляет PostgreSQL выполнять преобразование часовых поясов при чтении и записи временных отметок на основе вашей TimeZoneпеременной сеанса PostgreSQL . Вместо того, чтобы работать с часовыми поясами на самом краю вашего приложения, вы внедрили их в самое сердце, в саму связь с вашей базой данных. Вы должны позаботиться о том, чтобы всегда TimeZoneправильно настраивать PostgreSQL , добавляя еще одну ненужную точку сбоя и путаницы.

А для чего? Если вы следуете шаблону UTC везде, ваше приложение в любом случае имеет только временные метки UTC; так зачем просить вашу базу данных делать преобразования часовых поясов на них? Вы можете просто хранить их в timestamp without time zoneстолбце и обращаться с ним так, как будто это всегда UTC. Без конверсий, часовых поясов, без осложнений.

Шей Рожанский
источник
2
Я думаю, что сторонники timestamptz также поддерживают шаблон «UTC везде». Это просто правило применяется на уровне базы данных вместо того, чтобы полагаться только на разработчиков приложений / API? Если вы можете применить эту практику, почему бы и нет? Кроме того, вы можете просто установить, что все соединения postgres устанавливают свой часовой пояс в формате UTC. Даже если они этого не делают, формат ISO будет содержать смещение tz. Так разве это не то же самое, что UTC везде, но принудительно?
iamnat
3
Во-первых, если для вашего часового пояса PostgreSQL установлено значение, отличное от UTC, и вы используете timestamptz, ваша программа считывает временные метки, отличные от UTC. Это просто не шаблон «везде UTC», и в зависимости от языка вашего клиента может возникнуть или не возникнуть много сложностей. Либо вы везде по UTC, либо вы используете местные временные метки ....
Шей Рожанский
Во-вторых, еще раз, если вы везде используете UTC в своем UTC, просто нет смещения tz для отправки в формате ISO для ваших временных меток. Специфика будет варьироваться в зависимости от языка, но в идеале вы должны использовать тип клиента, который не способен представлять что-либо, кроме метки времени UTC (например, Instanceв NodaTime / JodaTime). Вы в основном описываете ситуацию, когда «UTC везде» почти соблюдается, или вроде как…
Shay Rojansky
Еще раз, очень легко представить себе новый экземпляр PostgreSQL, настроенный на каком-либо сервере, случайно сохранив часовой пояс локального компьютера, который настроен по умолчанию. Приложения читают с этого сервера и получают локальные временные метки в совершенно произвольном часовом поясе (в котором находится сервер). Зачем нам это дополнительное осложнение?
Шей Рожанский
1
Может, но тогда было бы еще меньше смысла использовать timestamptz. Весь смысл этого типа в том, чтобы выполнять преобразование часового пояса в виде значений, считанных и записанных в PostgreSQL (внутренне в базе данных отметка времени всегда сохраняется как UTC). Всегда установка часового пояса сеанса в UTC эффективно отключает эти преобразования, так зачем timestamptzвообще их использовать ? Иными словами, если значения в базе данных являются UTC, а значения, входящие и выходящие из базы данных, всегда являются UTC, то почему в вашей базе данных вообще есть информация о часовом поясе?
Шей Рожанский
2

dateМетка времени также не включает в себя информацию о временных зонах, тем не менее, многие люди используют его.

Конечно, это само по себе не является ответом.

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

Если часовой пояс всегда один и тот же или неявный, то лучше хранить его, чем не хранить (избыточная информация).

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


И наоборот, если вы проектируете или работаете в распределенной системе или в какой-либо системе, где части системы будут распределены по разным часовым поясам, это может рассматриваться как запрет на использование timestamp with timezone, хотя некоторые системы могут быть разработаны для запуска в одном часовом поясе, например, UTC. В этом случае логика часового пояса может быть перенесена на прикладной уровень - но я бы посчитал это анти-паттерном, да.

Колин т Харт
источник
Я понимаю, что в некоторых случаях это не мешает использовать timestamp without timezone, но покупает ли оно мне что-нибудь? Иначе зачем мне беспокоиться, если timestamp with timezone dataтип всегда одинаково или более уместен?
Маркус Юний Брутус
Не хранить избыточную информацию было бы моим главным аргументом. Я предполагаю, что арифметика с датами timestamp without timezoneтоже будет быстрее, но это, вероятно, важно, только если вы обрабатываете миллиарды строк ...
Colin 't Hart
1
@ Colin'tHart timestampи timestamptzоба хранятся одинаково. Информация о часовом поясе не сохраняется в a timestamptz, но вместо этого она преобразуется в UTC для хранения. Я бы сказал, всегда используйте, timestamptzкогда метки времени означают абсолютное время . Это все, что timestamptzзначит. Я написал об этом здесь .
fphilipe
2

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

При переключении с летнего времени на стандартное время час по местному времени повторяется (при условии, что разница равна часу). Там, где я живу, это обычно происходит около 2 часов ночи, поэтому местное время идет 01:58, 01:59, 01:00 и продвигается только до 02:00 в конце повторного часа.

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

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

Стив Фосдик
источник