PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Rappresentare un tempo futuro in PostgreSQL

Sembra che tu voglia memorizzare un ora locale rispetto a un determinato fuso orario. In tal caso, memorizza un timestamp (senza fuso orario) e il timezone in una colonna separata.

Ad esempio, supponiamo di voler registrare un evento che si verificherà alle 10:00 del 26 febbraio 2030 a Chicago e che debba essere alle 10:00 ora locale indipendentemente dalla regola del fuso orario in vigore in quella data.

Se il database memorizza il timestamp senza fuso orario:

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

Successivamente, puoi trovare la data e l'ora UTC dell'evento utilizzando

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 query restituisce la data e l'ora UTC, 2030-02-26 16:00:00 , che corrisponde a 2030-02-26 10:00:00 ora locale a Chicago.

Utilizzando AT TIME ZONE ritarda l'applicazione delle regole del fuso orario a quando viene eseguita la query invece di quando il timestamptz è stato inserito.

Utilizzando AT TIME ZONE su un timestamp localizza la data e l'ora nel fuso orario specificato, ma segnala la data e l'ora nel fuso orario dell'utente .Utilizzando AT TIME ZONE su un timestamptz converte la data e l'ora nel fuso orario specificato, quindi elimina l'offset, restituendo così un timestamp .Sopra, AT TIME ZONE viene utilizzato due volte:prima per localizzare un timestamp e poi per convertire il timestamptz restituito a un nuovo fuso orario (UTC). Il risultato è un timestamp in UTC.

Ecco un esempio, che mostra AT TIME ZONE comportamento di 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 e 2030-02-26 08:00:00-08 sono le stesse datetime ma riportate in fusi orari utente diversi. Questo mostra che le 10:00 a Chicago sono le 8:00 a Los Angeles (usando le attuali definizioni di fuso orario):

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

Un'alternativa all'utilizzo di AT TIME ZONE due volte è per impostare il fuso orario dell'utente a UTC . Allora potresti usare

select localtime AT TIME ZONE tzone

Nota che, se eseguito in questo modo, viene visualizzato un timestamptz viene restituito invece di un timestamp .

Fai attenzione perché la memorizzazione dell'ora locale può essere problematica perché possono esserci orari inesistenti e orari ambigui. Ad esempio, 2018-03-11 02:30:00 è un'ora locale inesistente in America/Chicago . Postgresql normalizza l'ora locale inesistente assumendo che si riferisca all'ora corrispondente dopo l'inizio dell'ora legale (DST) (come se qualcuno avesse dimenticato di impostare l'orologio in avanti):

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 esempio di ora locale ambigua è 2018-11-04 01:00:00 in America/Chicago . Si verifica due volte a causa dell'ora legale. Postgresql risolve questa ambiguità scegliendo l'ora successiva, dopo la fine dell'ora legale:

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

Nota che questo significa che non c'è modo di fare riferimento a 2018-11-04 06:00:00 UTC memorizzando l'ora locale in America/Chicago fuso orario:

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