"AT TIME ZONE" con il nome della zona bug PostgreSQL?


12

Stavo rispondendo a questa domanda di StackOverflow e ho trovato strani risultati:

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

e la prossima query

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

Sto usando PostgreSQL 9.1.2 e Ubuntu 12.04.
Ho appena verificato che il risultato 8.2.11 è lo stesso.

Secondo la documentazione non importa se uso il nome o l'abbreviazione.

è un insetto?
Sto facendo qualcosa di sbagliato?
Qualcuno può spiegare questo risultato?

MODIFICA Per il commento che CET non è Europa / Berlino.

Sto solo selezionando i valori da pg_timezone_names.

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

e

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

Durante l'inverno l'Europa / Berlino è +01. Durante l'estate è +02.

EDIT2 Nel 28-10-2012 il fuso orario è cambiato dall'ora legale all'orario invernale alle 2:00.
Questi due record hanno lo stesso valore in Europa / Berlino:

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

Questo suggerisce che se uso una delle abbreviazioni (CET o CEST) per l'intervallo di big data (ora legale e orario invernale) il risultato sarà errato per alcuni dei record. Andrà bene se uso "Europa / Berlino".

Ho cambiato l'ora di sistema in "2012-01-17" e anche pg_timezone_names è cambiato.

select * from  pg_timezone_names  where name ='Europe/Berlin';
     name      | abbrev | utc_offset | is_dst 
---------------+--------+------------+--------
 Europe/Berlin | CEST   | 02:00:00   | t

1
È certo che 2012-10-28 01:30:00sia CEST, non CET.
dezso,

1
Per quanto ne so non loCET è - almeno non durante i periodi di ora legale. Europe/Berlin
a_horse_with_no_name

Risposte:


9

In realtà, la documentazione afferma chiaramente che il nome del fuso orario e l'abbreviazione si comporteranno diversamente.

In breve, questa è la differenza tra abbreviazioni e nomi completi: le abbreviazioni rappresentano sempre un offset fisso rispetto a UTC, mentre la maggior parte dei nomi completi implica una regola locale per l'ora legale e quindi ha due possibili offset UTC. Riferimento

FWIW, lo stesso riferimento dice anche

Si consiglia di non utilizzare l'ora del tipo con il fuso orario (sebbene sia supportato da PostgreSQL per le applicazioni legacy e per la conformità allo standard SQL).


6

E non è ancora questo il senso! Ho riscontrato un problema molto simile qualche tempo fa.

I principali svantaggi delle abbreviazioni dei fusi orari sono già stati presentati qui: non tengono conto dell'ora legale (ora legale). Il grande professionista: semplicità che si traduce in prestazioni superiori . La presa in considerazione delle regole dell'ora legale rallenta il confronto dei nomi dei fusi orari . Le abbreviazioni del fuso orario sono semplici, offset simbolici del tempo, i nomi dei fusi orari sono soggetti a un insieme di regole in costante cambiamento. Ho eseguito benchmark in questa risposta correlata su SO , la differenza è notevole. Ma quando applicato a un set, in genere è necessario utilizzare i nomi dei fusi orari per coprire lo stato dell'ora legale eventualmente diverso per riga (e anche le differenze storiche).

Stiamo parlando di CET . La parte davvero difficile è che "CET" non è solo (ovviamente) un'abbreviazione di fuso orario , è anche un nome di fuso orario , almeno secondo la mia installazione (PostgreSQL 9.1.6 su Debian Squeeze con locale "de_AT.UTF-8 ") e tutti gli altri che ho visto finora. Cito questi dettagli, perché Postgres utilizza le informazioni sulla localizzazione del sistema operativo sottostante, se disponibile.

Vedi tu stesso:

SELECT * FROM pg_timezone_names WHERE name = 'CET';

SELECT * FROM pg_timezone_abbrevs WHERE abbrev = 'CET';

SQL Fiddle.

Postgres seleziona l'abbreviazione sul nome completo. Quindi, anche se ho trovato CET nei nomi dei fusi orari , l'espressione '2012-01-18 01:00 CET'::timestamptzviene interpretata in base alle regole leggermente diverse per le abbreviazioni dei fusi orari .

Se questa non è una pistola carica non so cosa sia.

Per evitare ambiguità, vai con il nome del fuso orario "Europa / Berlino" (o "Europa / Vienna" nel mio caso - che è effettivamente lo stesso, fatta eccezione per le differenze storiche). Trova maggiori dettagli sull'argomento nella domanda strettamente correlata che ho menzionato sopra .

In conclusione, vorrei esprimere il mio profondo disprezzo per il concetto idiota dell'ora legale. Dovrebbe essere rimosso dall'esistenza e non parlarne mai più.


3

Verificare questo:

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 a Berlino, non CET.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.