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

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


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 allows you to specify time zones in three different forms:

A full time zone name, for example America/New_York. The recognized time zone names are listed in the pg_timezone_names view (see Section 45.67). PostgreSQL uses the widely-used zoneinfo time zone data for this purpose, so the same names are also recognized by much other software.

A time zone abbreviation, for example PST. Such a specification merely defines a particular offset from UTC, in contrast to full time zone names which can imply a set of daylight savings transition-date rules as well. The recognized abbreviations are listed in the pg_timezone_abbrevs view (see Section 45.66). You cannot set the configuration parameters timezone or log_timezone to a time zone abbreviation, but you can use abbreviations in date/time input values and with the AT TIME ZONE operator.

Жирный Акцент мой.

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

My setup (more details added)

PostgreSQL 9.1.4 on Debian Squeeze (standard squeeze-backports from http://backports.debian.org/debian-backports)

Local timezone setting defaults to the system locale de_AT.UTF-8, but should be irrelevant for the example.

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" как часовой поясname вpg_timezone_names во всех них.

Ответы на вопрос(2)

Решение Вопроса

чтобы проверить наличие подозрений:

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

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

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 случаев часового поясаabbreviations в часовом поясеnames и не в состоянии понять, почему они там. Какова цель?

Среди них смещение времени (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

В этих случаях люди могут быть одурачены (как и я), глядя на TZname и нахождение временного смещения, которое фактически не применяется. Это неудачный дизайн - если не ошибка, по крайней мере,documentation bug.

Я не могу найти что-либо в руководстве о том, как неясности между часовым поясомnames а такжеabbreviations решены. Очевидно, что сокращения имеют приоритет.

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

If the token is a text string, match up with possible strings:

Do a binary-search table lookup for the token as a time zone abbreviation.

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

 21 авг. 2012 г., 01:43
Вау, я бы никогда не ожидал, что CET будет часовым поясомname, Используете ли вы базу данных часовых поясов, встроенную в PostgreSQL или (как это обычно бывает) из вашей ОС?

abbreviations не включают правила перехода на летнее время (DST), поскольку ониimply Штат. Здесь, на Среднем Западе США, мы используем CST (центральное стандартное время) в зимние месяцы и CDT (центральное летнее время) в остальное время года. Существуют аномальные области, которые не используют DST, поэтому это становится сложным.

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

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

test=# SELECT '2012-01-18 1:0 CET'::timestamptz AT TIME ZONE 'UTC'
test-#       ,'2012-01-18 1:0 Europe/Vienna'::timestamptz AT TIME ZONE 'UTC';
      timezone       |      timezone       
---------------------+---------------------
 2012-01-18 00:00:00 | 2012-01-18 00:00:00
(1 row)

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

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 Europe/Vienna'::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 row)

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 Europe/Vienna'::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 row)
 Erwin Brandstetter21 авг. 2012 г., 15:19
Спасибо за ответ! Я вижу, у вас есть часовой поясname & Quot; CET & Quot; в вашей системе. Я добавил резюме того, что мне кажется неправильным, в мой ответ.

Ваш ответ на вопрос