J'ai fait face au problème suivant ce matin:
select '2011-12-30 00:30:00'::timestamp without time zone AT TIME ZONE 'EST5EDT';
me renvoie 2011-12-30 05:30:00+00
la sorcière a tort.
Mais les prochaines requêtes ci-dessous:
select '2011-12-30 00:30:00'::timestamp without time zone AT TIME ZONE 'UTC-5';
select '2011-12-30 00:30:00' AT TIME ZONE 'EST5EDT';
je vois la bonne date 2011-12-29 19:30:00
Empêcher votre question sur mon fuseau horaire local:
SELECT current_setting('TIMEZONE');
current_setting
-----------------
UTC
(1 row)
Quelqu'un a-t-il répondu pourquoi postgresql convertit timestamp without time zone
d'une manière étrange et en prenant à la place 5 heures, il ajoute à la place?
timestamp without time zone AT TIME ZONE
réinterprète un timestamp
comme étant dans ce fuseau horaire pour le but de le convertir en UTC .
timestamp with time zone AT TIME ZONE
convertit un timestamptz
en timestamp
au fuseau horaire spécifié.
PostgreSQL utilise des fuseaux horaires ISO-8601, qui spécifient que l'est de Greenwich est positif ... sauf si vous utilisez un spécificateur de fuseau horaire POSIX, auquel cas il suit POSIX. La folie s'ensuit.
Les horodatages et les fuseaux horaires dans SQL sont horribles. Cette:
select '2011-12-30 00:30:00'::timestamp without time zone AT TIME ZONE 'EST5EDT';
interprète le littéral de type inconnu '2011-12-30 00:30:00'
comme timestamp without time zone
, ce que Pg suppose être dans la TimeZone locale, sauf indication contraire. Lorsque vous utilisez AT TIME ZONE
, Il est (selon la spécification) réinterprété en tant que timestamp with time zone
Dans le fuseau horaire EST5EDT
Puis stocké en temps absolu en UTC - il est donc converti à partir de EST5EDT
à UTC, c'est-à-dire que le décalage de fuseau horaire est soustrait . x - (-5)
est x + 5
.
Cet horodatage, ajusté au stockage UTC, est ensuite ajusté pour le paramètre TimeZone
de votre serveur pour l'affichage afin qu'il s'affiche à l'heure locale.
Si vous souhaitez plutôt dire "J'ai cet horodatage en heure UTC et souhaitez voir l'heure locale équivalente dans EST5EDT", si vous voulez être indépendant du paramètre TimeZone du serveur, vous devez écrire quelque chose comme:
select TIMESTAMP '2011-12-30 00:30:00' AT TIME ZONE 'UTC'
AT TIME ZONE 'EST5EDT';
Cela dit "Étant donné l'horodatage 2011-12-30 00:30:00, traitez-le comme un horodatage en UTC lors de la conversion en timestamptz, puis convertissez cet horodatage en heure locale dans EST5EDT".
Horrible, non? Je veux donner une entreprise à celui qui a décidé de la sémantique folle de AT TIME ZONE
- ça devrait vraiment être quelque chose comme timestamp CONVERT FROM TIME ZONE '-5'
et timestamptz CONVERT TO TIME ZONE '+5'
. De plus, timestamp with time zone
Devrait en fait porter son fuseau horaire avec lui, ne pas être stocké en UTC et converti automatiquement en heure locale.
Votre version originale "travaux":
select '2011-12-30 00:30:00' AT TIME ZONE 'EST5EDT';
ne sera correct que si TimeZone est défini sur UTC, car la conversion text-to-timestamptz suppose TimeZone lorsque celle-ci n'est pas spécifiée.
Deux problèmes s'annulent.
L'autre version qui semble fonctionner est indépendante de TimeZone, mais elle ne fonctionne que parce que deux problèmes s'annulent. Tout d'abord, comme expliqué ci-dessus, timestamp without time zone AT TIME ZONE
réinterprète l'horodatage comme étant dans ce fuseau horaire pour la conversion en un horodatage UTC; cela soustrait effectivement le décalage du fuseau horaire.
Cependant, pour des raisons que je dépasse mon ken, PostgreSQL utilise des horodatages avec le signe inverse de ce que j'ai l'habitude de voir la plupart des endroits. Voir la documentation :
Un autre problème à garder à l'esprit est que dans les noms de fuseau horaire POSIX, des décalages positifs sont utilisés pour les emplacements à l'ouest de Greenwich. Partout ailleurs, PostgreSQL suit la convention ISO-8601 selon laquelle les décalages de fuseau horaire positifs se trouvent à l'est de Greenwich.
Cela signifie que EST5EDT
Est identique à +5
, Et non -5
. C'est pourquoi cela fonctionne: parce que vous soustrayez le décalage tz sans l'ajouter, mais vous soustrayez un décalage négatif!
Ce dont vous auriez besoin pour le corriger est à la place:
select TIMESTAMP '2011-12-30 00:30:00' AT TIME ZONE 'UTC'
AT TIME ZONE '+5';