„AT TIME ZONE” z nazwą strefy Błąd PostgreSQL?

12

Odpowiedziałem na to pytanie dotyczące przepełnienia stosu i znalazłem dziwny wynik:

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

i następne zapytanie

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

Używam PostgreSQL 9.1.2 i Ubuntu 12.04.
Właśnie sprawdziłem, czy wynik 8.2.11 jest taki sam.

Zgodnie z dokumentacją nie ma znaczenia, czy użyję nazwy, czy skrótu.

Czy to błąd?
czy robię coś źle?
Czy ktoś może wyjaśnić ten wynik?

EDYCJA Za komentarz, że CET to nie Europa / Berlin.

Po prostu wybieram wartości z pg_timezone_names.

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

i

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

Zimą Europa / Berlin wynosi +01. Latem jest to +02.

EDYCJA 2 W strefie 28.10.2012 strefa czasowa zmieniła się z czasu letniego na zimowy o godzinie 2:00.
Te dwa rekordy mają tę samą wartość w Europie / Berlinie:

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

Sugeruje to, że jeśli użyję jednego ze skrótów (CET lub CEST) dla zakresu dużych zbiorów danych (czas letni i zimowy), wynik będzie nieprawidłowy dla niektórych rekordów. Będzie dobrze, jeśli użyję „Europa / Berlin”.

Zmieniłem czas systemowy na „17.01.2012” i pg_timezone_names również się zmieniło.

select * from  pg_timezone_names  where name ='Europe/Berlin';
     name      | abbrev | utc_offset | is_dst 
---------------+--------+------------+--------
 Europe/Berlin | CEST   | 02:00:00   | t
sufleR
źródło
1
Jest całkiem pewne, że 2012-10-28 01:30:00to CEST, a nie CET.
dezso,
1
O ile mi wiadomo nieCET jest - przynajmniej nie w czasach DST. Europe/Berlin
a_horse_w_no_name

Odpowiedzi:

9

W rzeczywistości dokumentacja wyraźnie mówi, że nazwa strefy czasowej i skrót będą zachowywać się inaczej.

Krótko mówiąc, jest to różnica między skrótami a pełnymi nazwami: skróty zawsze oznaczają stałe przesunięcie względem UTC, podczas gdy większość pełnych nazw sugeruje lokalną zasadę czasu letniego, a zatem mają dwa możliwe przesunięcia UTC. Odniesienie

FWIW, to samo powiedzenie również

Nie zalecamy używania typu time ze strefą czasową (chociaż jest obsługiwany przez PostgreSQL dla starszych aplikacji i dla zgodności ze standardem SQL).

Mike Sherrill „Cat Recall”
źródło
6

I to wciąż nie jest sedno! Jakiś czas temu spotkałem bardzo podobny problem .

Główne wady skrótów stref czasowych zostały już tutaj przedstawione: nie uwzględniają czasu letniego (DST). Główny plus: prostota zapewniająca najwyższą wydajność . Uwzględnienie reguł DST powoduje, że nazwy stref czasowych są powolne w porównaniu. Skróty stref czasowych są proste, symboliczne przesunięcia czasowe, nazwy stref czasowych podlegają ciągle zmieniającym się zestawowi reguł. Przeprowadziłem testy porównawcze w tej pokrewnej odpowiedzi na temat SO , różnica jest znacząca. Ale po zastosowaniu do zestawu zwykle konieczne jest użycie nazw stref czasowych, aby objąć możliwie inny status DST na wiersz (a także różnice historyczne).

Mówimy o CET . Naprawdę trudne jest to, że „CET” to nie tylko (oczywiście) A skrót strefy czasowej , jest również nazwa strefy czasowej , przynajmniej według mojej instalacji (PostgreSQL 9.1.6 na Debianie Squeeze z locale „de_AT.UTF-8 „) i wszystkie inne, które do tej pory widziałem. Wspominam o tych szczegółach, ponieważ Postgres korzysta z informacji regionalnych dotyczących podstawowego systemu operacyjnego, jeśli są one dostępne.

Sam zobacz:

SELECT * FROM pg_timezone_names WHERE name = 'CET';

SELECT * FROM pg_timezone_abbrevs WHERE abbrev = 'CET';

SQL Fiddle.

Postgres wybiera skrót nad pełną nazwą. Tak więc, mimo że znalazłem CET w nazwach stref czasowych , wyrażenie '2012-01-18 01:00 CET'::timestamptzjest interpretowane zgodnie z subtelnie różnymi regułami dla skrótów stref czasowych .

Jeśli to nie jest naładowany pistolet, nie wiem, co to jest.

Aby uniknąć niejasności, wybierz strefę czasową „Europa / Berlin” (lub „Europa / Wiedeń” w moim przypadku - która jest faktycznie taka sama, z wyjątkiem różnic historycznych). Znajdź więcej szczegółów na ten temat w ściśle powiązanym pytaniu, o którym wspomniałem powyżej .

Na zakończenie chciałbym wyrazić głęboką pogardę dla kretyńskiej koncepcji DST. Powinien zostać usunięty z istnienia i nigdy więcej o nim nie wspominany.

Erwin Brandstetter
źródło
3

Sprawdź to:

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 jest CEST w Berlinie, a nie CET.

dezso
źródło