web-dev-qa-db-ja.com

「AT TIME ZONE」とゾーン名PostgreSQLのバグ?

私はこれに答えていました 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の結果が同じであることを確認しただけです。

documentation によると、名前や略語を使用してもかまいません。

これはバグですか?
何か間違ったことをしていますか?
誰かがこの結果を説明できますか?

[〜#〜] edit [〜#〜]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です。

EDIT22012-10-28では、タイムゾーンが夏時間から冬時間の2:00に変更されました。
この2つのレコードは、ヨーロッパ/ベルリンで同じ値を持っています。

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
12
sufleR

実際、ドキュメントには、タイムゾーンの名前と省略形の動作が異なることが明確に記載されています。

つまり、これは略語とフルネームの違いです。略語は常にUTCからの固定オフセットを表しますが、フルネームのほとんどはローカルの夏時間規則を意味するため、2つの可能なUTCオフセットがあります。 参考

FWIW、その同じ参照はまた言います

Type time with time zoneを使用することはお勧めしません(レガシーアプリケーションおよびSQL標準への準拠のためにPostgreSQLでサポートされていますが)。

そしてそれはまだそれの要点ではありません!先ほど 非常によく似た問題 に遭遇しました。

タイムゾーンの略語の主な短所はすでにここに示されています。DST(夏時間)は考慮されていません。主な長所:シンプルで優れたパフォーマンス。 DSTルールを考慮すると、タイムゾーン名slowが比較されます。タイムゾーンの省略形は単純なシンボリック時間オフセットであり、タイムゾーン名は常に変化する一連のルールに従います。私は SOに関するこの関連回答 でベンチマークを実行しましたが、違いは顕著です。ただし、セットに適用する場合、通常はタイムゾーン名を使用して、行ごとに異なるDSTステータス(および履歴の違い)をカバーする必要があります

[〜#〜] cet [〜#〜]について話している。本当にトリッキーな部分は、 "CET"が(明らかに)タイムゾーンの省略形だけではなく、でもあるaタイムゾーン名、少なくとも私のインストールによると(ロケール「de_AT.UTF-8」を使用したDebian Squeeze上のPostgreSQL 9.1.6)そして私がこれまで見てきた他のすべて。 Postgresは、可能な場合は基盤となるOSのロケール情報を使用するため、これらの詳細について説明します。

自分で見て:

SELECT * FROM pg_timezone_names WHERE name = 'CET';

SELECT * FROM pg_timezone_abbrevs WHERE abbrev = 'CET';

SQLフィドル

Postgresはフルネームよりも略称を選びます。したがって、タイムゾーン名でCETを見つけたとしても、式'2012-01-18 01:00 CET'::timestamptzは、タイムゾーンの省略形の微妙に異なるルールに従って解釈されます。

それがロードされたフットガンでない場合、私は何をしているのかわかりません。

あいまいさを回避するには、タイムゾーン名 'Europe/Berlin'(または私の場合は 'Europe/Vienna'-これは、歴史的な違いを除いて実質的に同じです)を使用します。 上記で触れた密接に関連した質問 でトピックの詳細を確認してください。

最後に、DSTのモロニックコンセプトについて深く感じた軽蔑を表明します。それは存在から取り除かれ、二度と話されるべきではありません。

6

これをチェックして:

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はCETではなくベルリンのCESTです。

3
dezso