Det lyder som om du vil gemme en lokaltid med hensyn til en bestemt tidszone. I så fald skal du gemme et timestamp
(uden tidszone) og timezone
i en separat kolonne.
Antag for eksempel, at du vil optage en begivenhed, der finder sted kl. 10.00 den 26. februar 2030 i Chicago, og det skal være kl. 10.00 lokal tid uanset den tidszoneregel, der er gældende på den dato.
Hvis databasen gemmer tidsstemplet uden tidszone:
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 |
+---------------------+-----------------+
Så senere kan du finde UTC-dato-klokkeslættet for begivenheden ved hjælp af
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 |
+---------------------+
Forespørgslen returnerer UTC datetime, 2030-02-26 16:00:00
, hvilket svarer til 2030-02-26 10:00:00
lokaltid i Chicago.
Bruger AT TIME ZONE
forsinker anvendelsen af tidszonereglerne til hvornår forespørgslen er lavet i stedet for når timestamptz
blev indsat.
Bruger AT TIME ZONE
på et timestamp
lokaliserer dato og klokkeslæt til den givne tidszone, men rapporterer dato og klokkeslæt i brugerens tidszone .Brug af AT TIME ZONE
på en timestamptz
konverterer dato og klokkeslæt til den givne tidszone og dropper derefter forskydningen og returnerer således et timestamp
.Over, AT TIME ZONE
bruges to gange:først for at lokalisere et timestamp
og derefter konvertere den returnerede timestamptz
til en ny tidszone (UTC). Resultatet er et timestamp
i UTC.
Her er et eksempel, der demonstrerer AT TIME ZONE
s adfærd 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
og 2030-02-26 08:00:00-08
er de samme dato og klokkeslæt, men rapporteret i forskellige brugertidszoner. Dette viser kl. 10.00 i Chicago er kl. 8.00 i Los Angeles (ved at bruge de nuværende tidszonedefinitioner):
unutbu=# SELECT '2030-02-26 10:00:00-06'::timestamptz AT TIME ZONE 'America/Los_Angeles';
+---------------------+
| timezone |
+---------------------+
| 2030-02-26 08:00:00 |
+---------------------+
Et alternativ til at bruge AT TIME ZONE
to gange er at indstille brugerens tidszone
til UTC
. Så kunne du bruge
select localtime AT TIME ZONE tzone
Bemærk, at når det gøres på denne måde, en timestamptz
returneres i stedet for et timestamp
.
Vær opmærksom på, at lagring af lokale tider kan være problematisk, fordi der kan være ikke-eksisterende tidspunkter og tvetydige tidspunkter. For eksempel 2018-03-11 02:30:00
er en ikke-eksisterende lokaltid i America/Chicago
. Postgresql normaliserer ikke-eksisterende lokale tider ved at antage, at det refererer til den tilsvarende tid efter sommertid (DST) er begyndt (som om nogen glemte at stille deres ur frem):
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)
Et eksempel på en tvetydig lokaltid er 2018-11-04 01:00:00
i America/Chicago
. Det sker to gange på grund af sommertid. Postgresql løser denne tvetydighed ved at vælge det senere tidspunkt, efter sommertid er afsluttet:
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 |
+---------------------+
Bemærk, at det betyder, at der ikke er nogen måde at henvise til 2018-11-04 06:00:00 UTC
ved at gemme lokale tider i America/Chicago
tidszone:
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 |
+---------------------+