"AT TIME ZONE" avec le nom de zone Bogue PostgreSQL?


12

Je répondais à cette question de stackoverflow et j'ai trouvé un résultat étrange:

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

et la requête suivante

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

J'utilise PostgreSQL 9.1.2 et Ubuntu 12.04.
Je viens de vérifier que le résultat du 8.2.11 est le même.

Selon la documentation , peu importe si j'utilise un nom ou une abréviation.

Est-ce un bug?
Est-ce que je fais quelque chose de mal?
Quelqu'un peut-il expliquer ce résultat?

EDIT Pour le commentaire que CET n'est pas Europe / Berlin.

Je sélectionne simplement les valeurs de pg_timezone_names.

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

et

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

Pendant l'hiver Europe / Berlin est +01. En été, il fait +02.

EDIT2 En 2012-10-28, le fuseau horaire est passé de l'heure d'été à l'heure d'hiver à 2h00.
Ces deux records ont la même valeur en Europe / Berlin:

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

Cela suggère que si j'utilise l'une des abréviations (CET ou CEST) pour la plage de données volumineuses (heure d'été et heure d'hiver), le résultat sera incorrect pour certains enregistrements. Ce sera bien si j'utilise «Europe / Berlin».

J'ai changé l'heure système en '2012-01-17' et pg_timezone_names a également changé.

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

1
Il est certain que 2012-10-28 01:30:00c'est CEST, pas CET.
dezso

1
Pour autant que je sache, ce CETn'est pas le cas Europe/Berlin - du moins pas pendant l'heure d'été.
a_horse_with_no_name

Réponses:


9

En fait, la documentation indique clairement que le nom et l'abréviation du fuseau horaire se comporteront différemment.

En bref, c'est la différence entre les abréviations et les noms complets: les abréviations représentent toujours un décalage fixe par rapport à l'UTC, tandis que la plupart des noms complets impliquent une règle d'heure d'été locale, et ont donc deux décalages UTC possibles. Référence

FWIW, cette même référence dit également

Nous ne recommandons pas d'utiliser le type heure avec fuseau horaire (bien qu'il soit pris en charge par PostgreSQL pour les applications héritées et pour la conformité avec la norme SQL).


6

Et ce n'est toujours pas l'essentiel! J'ai rencontré un problème très similaire il y a quelque temps.

Les principaux inconvénients des abréviations de fuseaux horaires ont déjà été présentés ici: ils ne prennent pas en compte l'heure d'été (DST). Le principal avantage: la simplicité qui se traduit par des performances supérieures . La prise en compte des règles DST ralentit la comparaison des noms de fuseau horaire . Les abréviations de fuseau horaire sont des décalages horaires simples et symboliques, les noms de fuseau horaire sont soumis à un ensemble de règles en constante évolution. J'ai exécuté des repères dans cette réponse connexe sur SO , la différence est remarquable. Mais lorsqu'il est appliqué à un ensemble, il est généralement nécessaire d'utiliser des noms de fuseau horaire pour couvrir un état DST éventuellement différent par ligne (et également des différences historiques).

Nous parlons de CET . La partie vraiment délicate est que "CET" n'est pas seulement (évidemment) une abréviation de fuseau horaire , c'est aussi un nom de fuseau horaire , du moins selon mon installation (PostgreSQL 9.1.6 sur Debian Squeeze avec l'environnement local "de_AT.UTF-8 ") et tous les autres que j'ai vus jusqu'à présent. Je mentionne ces détails, car Postgres utilise les informations locales du système d'exploitation sous-jacent si elles sont disponibles.

Voir par vous-même:

SELECT * FROM pg_timezone_names WHERE name = 'CET';

SELECT * FROM pg_timezone_abbrevs WHERE abbrev = 'CET';

SQL Fiddle.

Postgres choisit l'abréviation sur le nom complet. Donc, même si j'ai trouvé CET dans les noms de fuseau horaire , l'expression '2012-01-18 01:00 CET'::timestamptzest interprétée selon les règles subtilement différentes des abréviations de fuseau horaire .

Si ce n'est pas une arme de poing chargée, je ne sais pas ce que c'est.

Pour éviter les ambiguïtés, choisissez le nom de fuseau horaire «Europe / Berlin» (ou «Europe / Vienne» dans mon cas - qui est en fait le même, sauf pour les différences historiques). Trouvez plus de détails sur le sujet sous la question étroitement liée que j'ai mentionnée ci-dessus .

En terminant, je voudrais exprimer mon mépris profondément ressenti pour le concept débile de DST. Il devrait être retiré de l'existence et ne plus jamais en parler.


3

Vérifie ça:

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 est CEST à Berlin, pas CET.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.