PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

PostgreSQL date() avec fuseau horaire

En gros, ce que vous voulez, c'est :

$ select starts_at AT TIME ZONE 'UTC' AT TIME ZONE 'US/Pacific' from schedules where id = 40

J'ai obtenu la solution de cet article ci-dessous, qui est tout simplement GOLD !!! Il explique très clairement ce problème non trivial, lisez-le si vous souhaitez mieux comprendre la gestion de pstgrsql TZ.

Exprimer les horodatages PostgreSQL sans zones en heure locale

Voici ce qui se passe. Tout d'abord, vous devez savoir que le fuseau horaire PST a 8 heures de retard sur le fuseau horaire UTC, par exemple le 1er janvier 2014, 16h30 PST (mercredi 01 janvier 2014 16:00:30 -0800) équivaut au 2 janvier 2014, 00:30 AM UTC (jeu 02 janvier 2014 00:00:30 +0000). Toute heure après 16h00 en PST passe au jour suivant, interprété comme UTC.

De plus, comme Erwin Brandstetter l'a mentionné ci-dessus, postresql a deux types de données d'horodatage, l'un avec un fuseau horaire et l'autre sans. Si vos horodatages incluent un fuseau horaire, alors un simple :

$ select starts_at AT TIME ZONE 'US/Pacific' from schedules where id = 40

marchera. Cependant, si votre horodatage est sans fuseau horaire, l'exécution de la commande ci-dessus ne fonctionnera pas, et vous devez D'ABORD convertir votre horodatage sans fuseau horaire en un horodatage avec un fuseau horaire, à savoir un fuseau horaire UTC, et UNIQUEMENT ENSUITE le convertir en votre 'PST' ou 'US/ Pacific' (qui sont les mêmes à quelques problèmes d'heure d'été. Je pense que vous devriez être d'accord avec l'un ou l'autre).

Permettez-moi de démontrer avec un exemple où je crée un horodatage sans fuseau horaire. Supposons par commodité que notre fuseau horaire local est bien "PST" (si ce n'était pas le cas, cela devient un peu plus compliqué, ce qui n'est pas nécessaire pour les besoins de cette explication).

Supposons que j'ai :

$ select timestamp '2014-01-2 00:30:00' AS a, timestamp '2014-01-2 00:30:00' AT TIME ZONE 'UTC' AS b,  timestamp '2014-01-2 00:30:00' AT TIME ZONE 'UTC' AT TIME ZONE 'PST' AS c, timestamp '2014-01-2 00:30:00' AT TIME ZONE 'PST' AS d

Cela donnera :

"a"=>"2014-01-02 00:30:00"   (This is the timezoneless timestamp)
"b"=>"2014-01-02 00:30:00+00" (This is the UTC TZ timestamp, note that up to a timezone, it is equivalent to the timezoneless one)
"c"=>"2014-01-01 16:30:00" (This is the correct 'PST' TZ conversion of the UTC timezone, if you read the documentation postgresql will not print the actual TZ for this conversion)
"d"=>"2014-01-02 08:30:00+00"

Le dernier horodatage est la raison de toute la confusion concernant la conversion de l'horodatage sans fuseau horaire de UTC en 'PST' dans postgresql. Quand on écrit :

timestamp '2014-01-2 00:30:00' AT TIME ZONE 'PST' AS d

Nous prenons un horodatage sans fuseau horaire et essayons de le convertir en 'PST TZ (nous supposons indirectement que postgresql comprendra que nous voulons qu'il convertisse l'horodatage d'un UTC TZ, mais postresql a ses propres plans !). En pratique, ce que fait postgresql, c'est qu'il prend l'horodatage sans fuseau horaire ('2014-01-2 00:30:00) et le traite comme s'il ÉTAIT DÉJÀ un horodatage 'PST' TZ (c'est-à-dire :2014-01-2 00:30 :00 -0800) et le convertit en fuseau horaire UTC !!! Donc, il le pousse en fait 8 heures en avant au lieu de reculer ! Ainsi nous obtenons (2014-01-02 08:30:00+00).

Quoi qu'il en soit, ce dernier comportement (non intuitif) est la cause de toutes les confusions. Lisez l'article si vous voulez une explication plus approfondie, j'ai effectivement obtenu des résultats un peu différents des leurs sur cette dernière partie, mais l'idée générale est la même.