«В ЗОНЕ ВРЕМЕНИ» с именем зоны Ошибка PostgreSQL?

12

Я отвечал на этот вопрос stackoverflow и нашел странный результат:

 select * from  pg_timezone_names where name = 'Europe/Berlin' ;
     name      | abbrev | utc_offset | is_dst 
---------------+--------+------------+--------
 Europe/Berlin | CET    | 01:00:00   | f

и следующий запрос

select id, 
  timestampwithtimezone, 
  timestampwithtimezone at time zone 'Europe/Berlin' as berlin, 
  timestampwithtimezone at time zone 'CET' as cet 
from data ;
 id  | timestampwithtimezone  |       berlin        |         cet         
 -----+------------------------+---------------------+---------------------
 205 | 2012-10-28 01:30:00+02 | 2012-10-28 01:30:00 | 2012-10-28 00:30:00
 204 | 2012-10-28 02:00:00+02 | 2012-10-28 02:00:00 | 2012-10-28 01:00:00
 203 | 2012-10-28 02:30:00+02 | 2012-10-28 02:30:00 | 2012-10-28 01:30:00
 202 | 2012-10-28 02:59:59+02 | 2012-10-28 02:59:59 | 2012-10-28 01:59:59
 106 | 2012-10-28 02:00:00+01 | 2012-10-28 02:00:00 | 2012-10-28 02:00:00

Я использую PostgreSQL 9.1.2 и Ubuntu 12.04.
Только что проверил, что на 8.2.11 результат такой же.

Согласно документации, не имеет значения, использую ли я имя или сокращение.

Это ошибка?
Я делаю что-то неправильно?
Может кто-нибудь объяснить этот результат?

РЕДАКТИРОВАТЬ Для комментария, что CET не Европа / Берлин.

Я просто выбираю значения из pg_timezone_names.

select * from  pg_timezone_names  where abbrev ='CEST';
 name | abbrev | utc_offset | is_dst 
------+--------+------------+--------

и

select * from  pg_timezone_names  where abbrev ='CET';
        name         | abbrev | utc_offset | is_dst 
---------------------+--------+------------+--------
 Africa/Tunis        | CET    | 01:00:00   | f
 Africa/Algiers      | CET    | 01:00:00   | f
 Africa/Ceuta        | CET    | 01:00:00   | f
 CET                 | CET    | 01:00:00   | f
 Atlantic/Jan_Mayen  | CET    | 01:00:00   | f
 Arctic/Longyearbyen | CET    | 01:00:00   | f
 Poland              | CET    | 01:00:00   | f
 .....

Зимой Европа / Берлин +01. Летом это +02.

EDIT2 В 2012-10-28 часовом поясе изменился с летнего времени на зимнее время в 2:00.
Эти две записи имеют одинаковое значение в Европе / Берлине:

204 | 2012-10-28 02:00:00+02 | 2012-10-28 02:00:00 | 2012-10-28 01:00:00
106 | 2012-10-28 02:00:00+01 | 2012-10-28 02:00:00 | 2012-10-28 02:00:00

Это говорит о том, что если я использую одно из сокращений (CET или CEST) для большого диапазона данных (летнее и зимнее время), результат будет неправильным для некоторых записей. Будет хорошо, если я буду использовать «Европа / Берлин».

Я изменил системное время на «2012-01-17», а также изменилось имя pg_timezone_names.

select * from  pg_timezone_names  where name ='Europe/Berlin';
     name      | abbrev | utc_offset | is_dst 
---------------+--------+------------+--------
 Europe/Berlin | CEST   | 02:00:00   | t
sufleR
источник
1
Я совершенно уверен, что 2012-10-28 01:30:00это CEST, а не CET.
Дезсо 20.12.12
1
Насколько я знаю CET, нет Europe/Berlin - по крайней мере, во времена DST.
a_horse_with_no_name

Ответы:

9

На самом деле, в документации ясно сказано, что название часового пояса и аббревиатура будут вести себя по-разному.

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

FWIW, та же самая ссылка также говорит

Мы не рекомендуем использовать тип time with time zone (хотя он поддерживается PostgreSQL для устаревших приложений и для соответствия стандарту SQL).

Майк Шеррилл 'Cat Recall'
источник
6

И это еще не суть! Я столкнулся с очень похожей проблемой некоторое время назад.

Основные недостатки аббревиатур часовых поясов уже представлены здесь: они не принимают во внимание летнее время (летнее время). Основное преимущество: простота, обеспечивающая превосходную производительность . Принимая во внимание правила летнего времени, имена часовых поясов становятся медленными по сравнению. Сокращения часового пояса - простые, символические смещения времени, названия часового пояса подчиняются постоянно меняющемуся набору правил. Я провел тесты в этом ответе на SO , разница замечательная. Но при применении к набору, как правило, необходимо использовать имена часовых поясов, чтобы охватить, возможно, различный статус DST для каждой строки (а также исторические различия).

Мы говорим о CET . Действительно сложная часть , что «CET» не только (очевидно) а зона сокращение времени , это также название часового пояса , по крайней мере , в соответствии с моей установки (PostgreSQL 9.1.6 на Debian Squeeze с локали «de_AT.UTF-8 ") и все остальные, которые я видел до сих пор. Я упоминаю эти детали, потому что Postgres использует информацию о локали базовой ОС, если она доступна.

Посмотреть на себя:

SELECT * FROM pg_timezone_names WHERE name = 'CET';

SELECT * FROM pg_timezone_abbrevs WHERE abbrev = 'CET';

SQL Fiddle.

Postgres выбирает аббревиатуру над полным именем. Таким образом, даже несмотря на то, что я нашел CET в именах часовых поясов , выражение '2012-01-18 01:00 CET'::timestamptzинтерпретируется в соответствии с слегка различающимися правилами для сокращений часовых поясов .

Если это не заряженный пулемет, я не знаю что.

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

В заключение я хотел бы высказать свое глубокое презрение к дебильной концепции DST. Это должно быть удалено из существования и никогда больше не упоминаться.

Эрвин Брандштеттер
источник
3

Проверь это:

select  
    '2012-10-28 02:30:00+02'::timestamp with time zone at time zone 'Europe/Berlin' as berlin,
    '2012-10-28 02:30:00+02'::timestamp with time zone at time zone 'CET' as cet,
    '2012-10-28 02:30:00+02'::timestamp with time zone at time zone 'CEST' as cest

+02 CEST в Берлине, а не CET.

Dezso
источник