web-dev-qa-db-fra.com

"Au fuseau horaire" avec nom de zone PostgreSQL Bug?

Je répondais à cela Stackoverflow question et trouvé étrange résultat:

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

et la prochaine requête

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.
[.____] Il suffit de vérifier que le résultat du 8.2.11 est le même.

Selon - documentation Peu importe si j'utilise le nom ou l'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 le CET n'est pas l'Europe/Berlin.

Je sélectionne simplement des 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
 .....

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

Edit2 En 2012-10-28 Timezone, a changé de temps d'été à hiver à 2h00.
[.____] Ces deux enregistrements 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 gamme de données Big Data (heure d'été et heure hivernale) aura mal pour certains enregistrements. Sera bon si j'utilise 'Europe/Berlin'.

J'ai changé le temps système vers '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
12
sufleR

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

En bref, il s'agit de la différence entre les abréviations et les noms complets: les abréviations représentent toujours un décalage correct de l'UTC, tandis que la plupart des noms complets impliquent une règle de temps de lumière de jour locale, et disposent donc de deux compensations UTC possibles. Référence

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

Nous ne recommandons pas d'utiliser le temps de type avec le 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).

Et ce n'est toujours pas le gist de celui-ci! J'ai couru dans n problème très similaire Il y a quelque temps.

Les principaux inconvénients des abréviations du fuseau horaire ont déjà été présentés ici: ils ne prennent pas en compte DST (heure de l'économie de jour). Le major Pro: la simplicité entraînant une supérieure performance. Prendre des règles de DST en compte rend les noms de fuseau horaire lent en comparaison. Les abréviations de fuseau horaire sont des compensations de temps symboliques, les noms de fuseau horaire sont soumis à un ensemble de règles en constante évolution. J'ai couru des points de repère dans cette réponse connexe sur SO , la différence est remarquable. Mais lorsqu'il est appliqué à un ensemble, c'est typiquement nécessaire Pour utiliser des noms de fuseau horaire pour couvrir éventuellement un statut DST par ligne (ainsi que des différences historiques).

Nous parlons de [~ # ~] CET [~ # ~ # ~]. La partie vraiment délicate est que "CET" n'est pas seulement (évidemment) A Abréviation de fuseau horaire, c'est aussi A Nom du fuseau horaire , Au moins, selon mon installation (PostgreSQL 9.1.6 sur Debian Squeeze avec locale "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 disponible.

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 Noms de fuseau horaire, l'expression '2012-01-18 01:00 CET'::timestamptz est interprété en fonction des règles subtilement différentes pour Abréviations de fuseau horaire.

Si ce n'est pas une pédale chargée, je ne sais pas ce qui est.

Pour éviter les ambiguïtés, allez avec le nom du fuseau horaire "Europe/Berlin" (ou "Europe/Vienne" dans mon cas - qui est effectivement la même chose, à l'exception des différences historiques). Trouvez plus de détails sur le sujet sous question étroitement liée que j'ai mentionnée ci-dessus .

En terminant, j'aimerais voter mon mépris profondément ressenti pour le concept moronique de DST. Il devrait être retiré de l'existence et jamais parlé de nouveau.

6
Erwin Brandstetter

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

3
dezso