Названия часовых поясов с одинаковыми свойствами дают разные результаты при применении к метке времени

Я просто провел час в отчаянии с несоответствием в этих результатах этих двух выражений:

db=# SELECT '2012-01-18 1:0 CET '::timestamptz AT TIME ZONE 'UTC' ,'2012-01-18 1:0 Europe/Vienna '::timestamptz AT TIME ZONE 'UTC'; timezone | timezone ---------------------+--------------------- 2012-08- 18 00:00:00 | 2012-08- 17 23:00:00 

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

Я проверил каталоги для этих двух названий часовых поясов. Они оба есть и выглядят одинаково:

 db=# SELECT * FROM pg_timezone_names WHERE name IN ('CET', 'Europe/Vienna'); name | abbrev | utc_offset | is_dst ---------------+--------+------------+-------- Europe/Vienna | CEST | 02:00:00 | t CET | CEST | 02:00:00 | t 

Я посоветовался с руководством PostgreSQL о часовых поясах :

PostgreSQL позволяет указать часовые пояса в трех разных формах:

Полное имя часового пояса, например America / New_York. Признанные имена часовых поясов перечислены в представлении pg_timezone_names (см. Раздел 45.67). PostgreSQL использует широко используемые данные зоны зоны zoneinfo для этой цели, поэтому одни и те же имена также распознаются многими другими программами.

Сокращение часового пояса, например PST. Такая спецификация просто определяет конкретное смещение от UTC, в отличие от полных имен часовых поясов, которые могут также подразумевать набор правил перехода на летнее время. Признанные сокращения перечислены в представлении pg_timezone_abbrevs (см. Раздел 45.66). Вы не можете установить временные параметры параметров конфигурации или log_timezone в сокращении часового пояса, но вы можете использовать сокращения в значениях ввода даты / времени и оператора AT TIME ZONE.

Смелый акцент Мой.

Так почему разница?

Моя настройка (добавлено больше деталей)

  • PostgreSQL 9.1.4 на Debian Squeeze (стандартное сжатие-backports из http://backports.debian.org/debian-backports )

  • Установка локального timezone умолчанию соответствует языку системы de_AT.UTF-8 , но для примера это не имеет значения.

 SELECT version(); version ------------------------------------------------------------------------------------------------------- PostgreSQL 9.1.4 on x86_64-unknown-linux-gnu, compiled by gcc-4.4.real (Debian 4.4.5-8) 4.4.5, 64-bit SHOW timezone_abbreviations; timezone_abbreviations ------------------------ Default 

.. который (я предполагаю) загружает аббревиатуры из этого файла: /usr/share/postgresql/9.1/timezonesets/Default

Я затрудняюсь, когда появляется название часового пояса CET . Но, очевидно, это есть в моих установках. Быстрый тест на sqlfiddle показывает тот же результат.

Я тестировал на двух разных серверах с аналогичной настройкой. Также с PostgreSQL 8.4. Нашел «CET» как имя часового пояса в pg_timezone_names во всех из них.

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

 SELECT * FROM pg_timezone_abbrevs WHERE abbrev IN ('CEST', 'CET'); abbrev | utc_offset | is_dst --------+------------+-------- CEST | 02:00:00 | t CET | 01:00:00 | f 

Как оказалось, есть также аббревиатура часового пояса по имени CET (что имеет смысл, «CET» является аббревиатурой). И похоже, что PostgreSQL выбирает аббревиатуру над полным именем. Итак, хотя я нашел CET в названиях часовых поясов, выражение «2012-01-18 1: 0 CET» :: timestamptz интерпретируется в соответствии с тонко различными правилами для сокращений часовых поясов.

 SELECT '2012-01-18 1:0 CEST'::timestamptz(0) ,'2012-01-18 1:0 CET'::timestamptz(0) ,'2012-01-18 1:0 Europe/Vienna'::timestamptz(0); timestamptz | timestamptz | timestamptz ------------------------+------------------------+------------------------ 2012-01-18 00:00:00+01 | 2012-01-18 01:00:00+01 | 2012-01-18 01:00:00+01 SELECT '2012-08-18 1:0 CEST'::timestamptz(0) ,'2012-08-18 1:0 CET'::timestamptz(0) ,'2012-08-18 1:0 Europe/Vienna'::timestamptz(0); timestamptz | timestamptz | timestamptz ------------------------+------------------------+------------------------ 2012-08-18 01:00:00+02 | 2012-08-18 02:00:00+02 | 2012-08-18 01:00:00+02 

Я нахожу 10 случаев сокращений часовых поясов в названиях часовых поясов и не понимаю, почему они есть. В чем цель?

Среди них смещение по времени ( utc_offset ) не utc_offset в четырех случаях из-за установки DST:

 SELECT n.*, a.* FROM pg_timezone_names n JOIN pg_timezone_abbrevs a ON a.abbrev = n.name WHERE n.utc_offset <> a.utc_offset; name | abbrev | utc_offset | is_dst | abbrev | utc_offset | is_dst ------+--------+------------+--------+--------+------------+-------- CET | CEST | 02:00:00 | t | CET | 01:00:00 | f EET | EEST | 03:00:00 | t | EET | 02:00:00 | f MET | MEST | 02:00:00 | t | MET | 01:00:00 | f WET | WEST | 01:00:00 | t | WET | 00:00:00 | f 

В этих случаях люди могут быть обмануты (как и я), просматривая имя tz и находя временное смещение, которое на самом деле не применяется. Это неудачный дизайн – если не ошибка, по крайней мере ошибка документации .

В руководстве не могу найти ничего о том, как разрешаются неоднозначности между названиями часовых поясов и аббревиатурами . Очевидно, аббревиатуры имеют приоритет.

Приложение B.1. Интерпретация ввода-вывода по дате / времени указывает на поиск сокращений часовых поясов, но остается неясным, как идентифицируются имена часовых поясов и какие из них имеют приоритет в случае двусмысленного токена.

Если токен – текстовая строка, совпадают с возможными строками:

Сделайте поиск таблицы бинарного поиска для токена в виде сокращения временного интервала.

Ну, в этом предложении есть небольшой намек на то, что аббревиатуры на первом месте, но ничего окончательного. Кроме того, в обеих таблицах есть abbrev столбца, pg_timezone_names и pg_timezone_abbrevs

Причина, по которой сокращения в часовых поясах не include переходные правила перехода на летнее время (DST), заключается в том, что они имеют тенденцию подразумевать состояние. Здесь, на Среднем Западе США, мы находимся в КНТ (Центральное стандартное время) в зимние месяцы и на CDT (Central Daylight Time) до конца года. Есть аномальные области, которые не используют DST, поэтому он становится сложным.

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

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

 test = # SELECT '2012-01-18 1: 0 CET' :: timestamptz AT TIME ZONE 'UTC'
 test- #, '2012-01-18 1: 0 Европа / Вена' :: timestamptz AT TIME ZONE 'UTC';
       часовой пояс |  часовой пояс       
 --------------------- + ---------------------
  2012-01-18 00:00:00 |  2012-01-18 00:00:00
 (1 ряд)

 test = # SELECT * FROM pg_timezone_names WHERE name IN ('CET', 'Europe / Vienna');
      имя |  аббревиатура |  utc_offset |  is_dst 
 --------------- + -------- + ------------ + --------
  CET |  CEST |  02:00:00 |  T
  Европа / Вена |  CEST |  02:00:00 |  T
 (2 строки)
 test = # SELECT * FROM pg_timezone_abbrevs
 test- # WHERE abbrev IN ('CEST', 'CET');
  аббревиатура |  utc_offset |  is_dst 
 -------- + ------------ + --------
  CEST |  02:00:00 |  T
  CET |  01:00:00 |  е
 (2 строки)

 test = # SELECT '2012-01-18 1: 0 CEST' :: timestamptz (0)
 test- #, '2012-01-18 1: 0 CET' :: timestamptz (0)
 test- #, '2012-01-18 1: 0 Европа / Вена' :: timestamptz (0);
       timestamptz |  timestamptz |  timestamptz       
 ------------------------ + ------------------------ + ------------------------
  2012-01-17 17: 00: 00-06 |  2012-01-17 18: 00: 00-06 |  2012-01-17 18: 00: 00-06
 (1 ряд)

 test = # SELECT '2012-08-18 1: 0 CEST' :: timestamptz (0)
 test- #, '2012-08-18 1: 0 CET' :: timestamptz (0)
 test- #, '2012-08-18 1: 0 Европа / Вена' :: timestamptz (0);
       timestamptz |  timestamptz |  timestamptz       
 ------------------------ + ------------------------ + ------------------------
  2012-08-17 18: 00: 00-05 |  2012-08-17 19: 00: 00-05 |  2012-08-17 18: 00: 00-05
 (1 ряд)
  • Веб-сервис - текущий часовой пояс для города?
  • Установите системный часовой пояс из .NET.
  • Управление календарем, датой и временем java для приложения с несколькими часовыми поясами
  • Как перевести между часовыми поясами Windows и IANA?
  • Как получить часовой пояс из местоположения с использованием координат широты и долготы?
  • Разница между UTC и стандартным временем GMT в .NET.
  • Как преобразовать время в часовой пояс устройства iPhone?
  • Получение даты с на несколько часов
  • Заставить часовой пояс Java как GMT / UTC
  • Преобразование дат UTC в другие часовые пояса
  • Часовой пояс с рельсами 3
  • Давайте будем гением компьютера.