sql >> Databasteknik >  >> RDS >> PostgreSQL

Representerar en framtida tid i PostgreSQL

Det låter som att du vill lagra en lokal tid med avseende på en viss tidszon. Lagra i så fall en timestamp (utan tidszon) och timezone i en separat kolumn.

Anta till exempel att du vill spela in en händelse som inträffar kl. 10.00 den 26 februari 2030 i Chicago och att den måste vara kl. 10.00 lokal tid oavsett vilken tidszonsregel som gäller det datumet.

Om databasen lagrar tidsstämpeln utan tidszon:

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

Senare kan du hitta UTC-datumtid för händelsen med

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

Frågan returnerar UTC datetime, 2030-02-26 16:00:00 , vilket motsvarar 2030-02-26 10:00:00 lokaltid i Chicago.

Använder AT TIME ZONE försenar tillämpningen av tidszonsreglerna till när frågan görs istället för när timestamptz infogades.

Använder AT TIME ZONE på en timestamp lokaliserar datum och tid till den givna tidszonen, men rapporterar datum och tid i användarens tidszon .Använder AT TIME ZONE på en timestamptz konverterar datetime till den givna tidszonen, tappar sedan offseten och returnerar därmed en timestamp .Ovan, AT TIME ZONE används två gånger:först för att lokalisera en timestamp och nästa för att konvertera den returnerade timestamptz till en ny tidszon (UTC). Resultatet är en timestamp i UTC.

Här är ett exempel som visar AT TIME ZONE s beteende på 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 och 2030-02-26 08:00:00-08 är samma datum och tider men rapporteras i olika användartidszoner. Detta visar att 10:00 i Chicago är 8:00 i Los Angeles (med nuvarande tidszonsdefinitioner):

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

Ett alternativ till att använda AT TIME ZONE två gånger är att ställa in användarens tidszon till UTC . Då kan du använda

select localtime AT TIME ZONE tzone

Observera att när du gör det på detta sätt, en timestamptz returneras istället för en timestamp .

Tänk på att det kan vara problematiskt att lagra lokala tider eftersom det kan finnas obefintliga tider och oklara tider. Till exempel 2018-03-11 02:30:00 är en obefintlig lokaltid i America/Chicago . Postgresql normaliserar obefintliga lokala tider genom att anta att det refererar till motsvarande tid efter att sommartid (DST) har börjat (som om någon glömt att ställa klockan framåt):

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)

Ett exempel på en tvetydig lokaltid är 2018-11-04 01:00:00 i America/Chicago . Det inträffar två gånger på grund av sommartid. Postgresql löser denna tvetydighet genom att välja den senare tidpunkten, efter sommartid:

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

Observera att detta betyder att det inte finns något sätt att referera till 2018-11-04 06:00:00 UTC genom att lagra lokala tider i America/Chicago tidszon:

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


  1. MySQL :När proceduren lagras är parameternamnet detsamma som tabellkolumnnamnet

  2. SQL DROP TABLE för nybörjare

  3. MySQL:hur kan jag se ALLA begränsningar på en tabell?

  4. hur kan jag returnera flera databasposter från en klass i OOP-programmering