Het klinkt alsof je een localtime . wilt opslaan met betrekking tot een bepaalde tijdzone. Bewaar in dat geval een timestamp
(zonder tijdzone) en de timezone
in een aparte kolom.
Stel dat u een gebeurtenis wilt opnemen die op 26 februari 2030 om 10.00 uur in Chicago zal plaatsvinden en dat het om 10.00 uur lokale tijd moet zijn. ongeacht de tijdzoneregel die op die datum van kracht is.
Als de database de tijdstempel zonder tijdzone opslaat:
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 |
+---------------------+-----------------+
Later kunt u de UTC-datum/tijd van het evenement vinden met
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 |
+---------------------+
De query retourneert de UTC datetime, 2030-02-26 16:00:00
, wat overeenkomt met 2030-02-26 10:00:00
lokale tijd in Chicago.
AT TIME ZONE
gebruiken vertraagt de toepassing van de tijdzoneregels tot wanneer de vraag wordt gemaakt in plaats van wanneer de timestamptz
is ingevoegd.
AT TIME ZONE
gebruiken op een timestamp
lokaliseert de datetime naar de opgegeven tijdzone, maar rapporteert de datetime in de tijdzone van de gebruiker .Gebruik AT TIME ZONE
op een timestamptz
converteert de datetime naar de opgegeven tijdzone, laat vervolgens de offset vallen, waardoor een timestamp
wordt geretourneerd .Boven, AT TIME ZONE
wordt twee keer gebruikt:eerst om een timestamp
te lokaliseren en vervolgens om de geretourneerde timestamptz
. te converteren naar een nieuwe tijdzone (UTC). Het resultaat is een timestamp
in UTC.
Hier is een voorbeeld van AT TIME ZONE
's gedrag op 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
en 2030-02-26 08:00:00-08
zijn dezelfde datetimes maar gerapporteerd in verschillende gebruikerstijdzones. Dit toont 10 uur in Chicago is 8 uur in Los Angeles (met huidige tijdzonedefinities):
unutbu=# SELECT '2030-02-26 10:00:00-06'::timestamptz AT TIME ZONE 'America/Los_Angeles';
+---------------------+
| timezone |
+---------------------+
| 2030-02-26 08:00:00 |
+---------------------+
Een alternatief voor het gebruik van AT TIME ZONE
tweemaal is om de gebruikerstijdzone in te stellen
naar UTC
. Dan zou je kunnen gebruiken
select localtime AT TIME ZONE tzone
Merk op dat wanneer u dit op deze manier doet, een timestamptz
wordt geretourneerd in plaats van een timestamp
.
Houd er rekening mee dat het opslaan van lokale tijden problematisch kan zijn omdat er niet-bestaande tijden en onduidelijke tijden kunnen zijn. Bijvoorbeeld, 2018-03-11 02:30:00
is een niet-bestaande lokale tijd in America/Chicago
. Postgresql normaliseert niet-bestaande lokale tijden door aan te nemen dat het verwijst naar de overeenkomstige tijd nadat de zomertijd (DST) is begonnen (alsof iemand is vergeten de klok vooruit te zetten):
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)
Een voorbeeld van een ambigue lokale tijd is 2018-11-04 01:00:00
in America/Chicago
. Het komt twee keer voor vanwege de DST. Postgresql lost deze dubbelzinnigheid op door een later tijdstip te kiezen, nadat de DST is afgelopen:
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 |
+---------------------+
Merk op dat dit betekent dat er geen manier is om te verwijzen naar 2018-11-04 06:00:00 UTC
door lokale tijden op te slaan in de America/Chicago
tijdzone:
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 |
+---------------------+