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

Représenter un temps futur dans PostgreSQL

Il semble que vous souhaitiez stocker une heure locale par rapport à un certain fuseau horaire. Dans ce cas, stockez un timestamp (sans fuseau horaire) et le timezone dans une colonne séparée.

Par exemple, supposons que vous souhaitiez enregistrer un événement qui se produira à 10 h 00 le 26 février 2030 à Chicago et qu'il doit avoir lieu à 10 h 00 heure locale quelle que soit la règle de fuseau horaire en vigueur à cette date.

Si la base de données stocke l'horodatage sans fuseau horaire :

unutbu=# select '2030-02-26 10:00:00'::timestamp as localtime, 'America/Chicago' AS tzone;
+---------------------+-----------------+
|      localtime      |      tzone      |
+---------------------+-----------------+
| 2030-02-26 10:00:00 | America/Chicago |
+---------------------+-----------------+

Puis plus tard, vous pouvez trouver la date et l'heure UTC de l'événement en utilisant

unutbu=# select '2030-02-26 10:00:00'::timestamp AT TIME ZONE 'America/Chicago' AT TIME ZONE 'UTC';
+---------------------+
|      timezone       |
+---------------------+
| 2030-02-26 16:00:00 |
+---------------------+

La requête renvoie la date et l'heure UTC, 2030-02-26 16:00:00 , ce qui correspond à 2030-02-26 10:00:00 heure locale à Chicago.

Utiliser AT TIME ZONE retarde l'application des règles de fuseau horaire au moment où la requête est faite au lieu du moment où le timestamptz a été inséré.

Utiliser AT TIME ZONE sur un timestamp localise la date et l'heure dans le fuseau horaire donné, mais rapports la date et l'heure dans le fuseau horaire de l'utilisateur .En utilisant AT TIME ZONE sur un timestamptz convertit la date/heure dans le fuseau horaire donné, puis supprime le décalage, renvoyant ainsi un timestamp .Ci-dessus, AT TIME ZONE est utilisé deux fois :d'abord pour localiser un timestamp et ensuite pour convertir le timestamptz renvoyé vers un nouveau fuseau horaire (UTC). Le résultat est un timestamp en UTC.

Voici un exemple, démontrant AT TIME ZONE Comportement de sur timestamp s :

unutbu=# SET timezone = 'America/Chicago';
unutbu=# SELECT '2030-02-26 10:00:00'::timestamp AT TIME ZONE 'America/Chicago';
+------------------------+
|        timezone        |
+------------------------+
| 2030-02-26 10:00:00-06 |
+------------------------+

unutbu=# SET timezone = 'America/Los_Angeles';
unutbu=# SELECT '2030-02-26 10:00:00'::timestamp AT TIME ZONE 'America/Chicago';
+------------------------+
|        timezone        |
+------------------------+
| 2030-02-26 08:00:00-08 |
+------------------------+

2030-02-26 10:00:00-06 et 2030-02-26 08:00:00-08 sont les mêmes datetimes mais signalés dans différents fuseaux horaires d'utilisateur. Cela montre que 10 h 00 à Chicago correspond à 8 h 00 à Los Angeles (selon les définitions de fuseau horaire actuelles) :

unutbu=# SELECT '2030-02-26 10:00:00-06'::timestamptz AT TIME ZONE 'America/Los_Angeles';
+---------------------+
|      timezone       |
+---------------------+
| 2030-02-26 08:00:00 |
+---------------------+

Une alternative à l'utilisation de AT TIME ZONE deux fois est de définir le fuseau horaire de l'utilisateur à UTC . Ensuite, vous pouvez utiliser

select localtime AT TIME ZONE tzone

Notez que lorsque cela est fait de cette façon, un timestamptz est renvoyé à la place d'un timestamp .

Attention, le stockage des heures locales peut être problématique car il peut y avoir des heures inexistantes et des heures ambiguës.Par exemple, 2018-03-11 02:30:00 est une heure locale inexistante en America/Chicago . Postgresql normalise les heures locales inexistantes en supposant qu'elles se réfèrent à l'heure correspondante après le début de l'heure d'été (DST) (comme si quelqu'un avait oublié d'avancer son horloge) :

unutbu=# select '2018-03-11 02:30:00'::timestamp AT TIME ZONE 'America/Chicago' AT TIME ZONE 'UTC';
+---------------------+
|      timezone       |
+---------------------+
| 2018-03-11 08:30:00 |
+---------------------+
(1 row)

unutbu=# select '2018-03-11 03:30:00'::timestamp AT TIME ZONE 'America/Chicago' AT TIME ZONE 'UTC';
+---------------------+
|      timezone       |
+---------------------+
| 2018-03-11 08:30:00 |
+---------------------+
(1 row)

Un exemple d'heure locale ambiguë est 2018-11-04 01:00:00 en America/Chicago . Il se produit deux fois en raison de l'heure d'été. Postgresql résout cette ambiguïté en choisissant l'heure la plus tardive, après la fin de l'heure d'été :

unutbu=# select '2018-11-04 01:00:00'::timestamp AT TIME ZONE 'America/Chicago' AT TIME ZONE 'UTC';
+---------------------+
|      timezone       |
+---------------------+
| 2018-11-04 07:00:00 |
+---------------------+

Notez que cela signifie qu'il n'y a aucun moyen de faire référence à 2018-11-04 06:00:00 UTC en stockant les heures locales dans America/Chicago fuseau horaire :

unutbu=# select '2018-11-04 00:59:59'::timestamp AT TIME ZONE 'America/Chicago' AT TIME ZONE 'UTC';
+---------------------+
|      timezone       |
+---------------------+
| 2018-11-04 05:59:59 |
+---------------------+