"AT TIME ZONE" mit Zonenname PostgreSQL-Fehler?

12

Ich beantwortete diese Stapelüberlauf- Frage und fand ein merkwürdiges Ergebnis:

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

und nächste Abfrage

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

Ich benutze PostgreSQL 9.1.2 und Ubuntu 12.04.
Habe gerade überprüft, dass am 8.2.11 das selbe Ergebnis vorliegt.

Laut Dokumentation ist es egal, ob ich Namen oder Abkürzungen benutze.

Ist das ein Bug?
Mache ich etwas falsch?
Kann jemand dieses Ergebnis erklären?

EDIT Für den Hinweis, dass CET nicht Europa / Berlin ist.

Ich wähle nur Werte aus pg_timezone_names aus.

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

und

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
 .....

Im Winter ist Europa / Berlin +01. Im Sommer ist es +02.

EDIT2 In 2012-10-28 Zeitzone hat Wechsel von Sommerzeit auf Winterzeit um 2:00.
Diese beiden Datensätze haben in Europa / Berlin den gleichen Wert:

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

Dies deutet darauf hin, dass, wenn ich eine der Abkürzungen (MEZ oder MESZ) für den Big-Data-Bereich (Sommerzeit und Winterzeit) verwende, das Ergebnis für einige Datensätze falsch ist. Wird gut, wenn ich 'Europa / Berlin' benutze.

Ich habe die Systemzeit auf '2012-01-17' geändert und pg_timezone_names hat sich ebenfalls geändert.

select * from  pg_timezone_names  where name ='Europe/Berlin';
     name      | abbrev | utc_offset | is_dst 
---------------+--------+------------+--------
 Europe/Berlin | CEST   | 02:00:00   | t
sufleR
quelle
1
Es ist ziemlich sicher, dass 2012-10-28 01:30:00MESZ, nicht MEZ ist.
Dezso
1
Soweit ich weiß , CETist nicht Europe/Berlin - zumindest nicht während DST Zeiten.
a_horse_with_no_name 20.12.12

Antworten:

9

Tatsächlich wird in der Dokumentation deutlich, dass sich der Name und die Abkürzung der Zeitzone unterschiedlich verhalten.

Kurz gesagt, dies ist der Unterschied zwischen Abkürzungen und vollständigen Namen: Abkürzungen stellen immer einen festen Versatz zur UTC dar, wohingegen die meisten vollständigen Namen eine lokale Sommerzeitregel implizieren und daher zwei mögliche UTC-Versätze aufweisen. Referenz

FWIW, die gleiche Referenz sagt auch

Es wird nicht empfohlen, den Typ Zeit mit Zeitzone zu verwenden (obwohl er von PostgreSQL für ältere Anwendungen und zur Einhaltung des SQL-Standards unterstützt wird).

Mike Sherrill 'Cat Recall'
quelle
6

Und das ist immer noch nicht alles! Ich bin vor einiger Zeit auf ein sehr ähnliches Problem gestoßen.

Die wichtigsten Nachteile von Zeitzonenabkürzungen wurden hier bereits dargestellt: Sie berücksichtigen nicht die Sommerzeit (DST). Der große Vorteil: Einfachheit, die zu überlegener Leistung führt . Durch die Berücksichtigung von DST-Regeln werden Zeitzonennamen im Vergleich langsamer . Zeitzonenabkürzungen sind einfache, symbolische Zeitversätze, Zeitzonennamen unterliegen einem sich ständig ändernden Regelwerk. Ich habe Benchmarks in dieser verwandten Antwort auf SO durchgeführt , der Unterschied ist bemerkenswert. Bei der Anwendung auf einen Satz ist es jedoch in der Regel erforderlich , Zeitzonennamen zu verwenden, um möglicherweise unterschiedliche DST-Status pro Zeile (und auch historische Unterschiede) abzudecken.

Wir sprechen von MEZ . Der wirklich knifflige Teil ist, dass "CET" nicht nur (offensichtlich) eine Abkürzung für eine Zeitzone ist , sondern auch ein Zeitzonenname , zumindest gemäß meiner Installation (PostgreSQL 9.1.6 unter Debian Squeeze mit dem Gebietsschema "de_AT.UTF-8") ") und alle anderen, die ich bisher gesehen habe. Ich erwähne diese Details, da Postgres die Gebietsschemainformationen des zugrunde liegenden Betriebssystems verwendet, sofern verfügbar.

Überzeugen Sie sich selbst:

SELECT * FROM pg_timezone_names WHERE name = 'CET';

SELECT * FROM pg_timezone_abbrevs WHERE abbrev = 'CET';

SQL-Geige.

Postgres wählt die Abkürzung über den vollständigen Namen. Obwohl ich CET in den Zeitzonennamen gefunden habe , wird der Ausdruck '2012-01-18 01:00 CET'::timestamptzgemäß den subtil unterschiedlichen Regeln für Zeitzonenabkürzungen interpretiert .

Wenn das keine geladene Waffe ist, weiß ich nicht, was es ist.

Um Unklarheiten zu vermeiden, verwenden Sie den Zeitzonennamen "Europa / Berlin" (oder in meinem Fall "Europa / Wien" - abgesehen von historischen Unterschieden praktisch identisch). Weitere Details zu diesem Thema finden Sie unter der oben erwähnten eng verwandten Frage .

Abschließend möchte ich meine tief empfundene Verachtung für das schwachsinnige Konzept der Sommerzeit zum Ausdruck bringen. Es sollte aus der Existenz entfernt und nie wieder erwähnt werden.

Erwin Brandstetter
quelle
3

Überprüfen Sie dies:

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 ist MESZ in Berlin, nicht MEZ.

dezso
quelle