Вопрос по postgresql, timezone, datetime – Имена часовых поясов с одинаковыми свойствами дают другой результат при применении к метке времени
Я только что провел час в отчаянии из-за расхождений в этих результатах этих двух выражений:
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
во всех них.
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)
чтобы проверить наличие подозрений:
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
...