Wygląda na to, że chcesz zapisać czas lokalny w odniesieniu do określonej strefy czasowej. W takim przypadku zapisz timestamp (bez strefy czasowej) i timezone w osobnej kolumnie.
Załóżmy na przykład, że chcesz nagrać wydarzenie, które będzie miało miejsce o godzinie 10 rano 26 lutego 2030 roku w Chicago i musi mieć miejsce o godzinie 10 rano czasu lokalnego niezależnie od reguły strefy czasowej obowiązującej w tym dniu.
Jeśli baza danych przechowuje znacznik czasu bez strefy czasowej:
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 |
+---------------------+-----------------+
Później możesz znaleźć datę i godzinę wydarzenia UTC za pomocą
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 |
+---------------------+
Zapytanie zwraca datę i godzinę UTC, 2030-02-26 16:00:00 , co odpowiada 2030-02-26 10:00:00 czas lokalny w Chicago.
Korzystanie z AT TIME ZONE opóźnia zastosowanie reguł strefy czasowej do kiedy zapytanie jest wykonane zamiast kiedy timestamptz został wstawiony.
Korzystanie z AT TIME ZONE na timestamp lokalizuje datę i godzinę na podaną strefę czasową, ale raporty data i godzina w strefie czasowej użytkownika .Korzystanie z AT TIME ZONE na timestamp konwertuje datę i godzinę na podaną strefę czasową, a następnie usuwa przesunięcie, zwracając w ten sposób timestamp .Powyżej, AT TIME ZONE jest używany dwukrotnie:najpierw do lokalizacji timestamp a następnie przekonwertować zwrócony timestamp do nowej strefy czasowej (UTC). Wynikiem jest timestamp w UTC.
Oto przykład demonstrujący AT TIME ZONE zachowanie na 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 i 2030-02-26 08:00:00-08 to te same daty i godziny, ale zgłoszone w różnych strefach czasowych użytkownika. To pokazuje, że 10 rano w Chicago jest 8 rano w Los Angeles (przy użyciu aktualnych definicji stref czasowych):
unutbu=# SELECT '2030-02-26 10:00:00-06'::timestamptz AT TIME ZONE 'America/Los_Angeles';
+---------------------+
| timezone |
+---------------------+
| 2030-02-26 08:00:00 |
+---------------------+
Alternatywa dla używania AT TIME ZONE dwa razy to ustawienie strefy czasowej użytkownika
do UTC . Wtedy możesz użyć
select localtime AT TIME ZONE tzone
Zauważ, że gdy zrobisz to w ten sposób, timestamp jest zwracany zamiast timestamp .
Pamiętaj, że przechowywanie czasów lokalnych może być problematyczne, ponieważ mogą istnieć nieistniejące czasy i niejednoznaczne czasy. Na przykład 2018-03-11 02:30:00 to nieistniejący czas lokalny w America/Chicago . Postgresql normalizuje nieistniejący czas lokalny, zakładając, że odnosi się on do odpowiedniego czasu po rozpoczęciu czasu letniego (DST) (jakby ktoś zapomniał przestawić swój zegar do przodu):
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)
Przykładem niejednoznacznego czasu lokalnego jest 2018-11-04 01:00:00 w America/Chicago . Występuje dwukrotnie z powodu czasu letniego. Postgresql rozwiązuje tę niejednoznaczność, wybierając późniejszy czas, po zakończeniu czasu letniego:
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 |
+---------------------+
Zauważ, że oznacza to, że nie ma możliwości odwołania się do 2018-11-04 06:00:00 UTC przechowując czasy lokalne w America/Chicago strefa czasowa:
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 |
+---------------------+