PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Behandeln Sie TIME WITH TIME ZONE in PostgreSQL richtig

Sie haben Folgendes behauptet:

Also niemals Überqueren Sie die Datumsgrenze innerhalb derselben Reihe. Ich schlage vor, 1x date zu speichern 3x time und die Zeitzone (als text oder FK-Spalte):

CREATE TABLE legacy_table (
   event_id      bigint PRIMARY KEY NOT NULL
 , report_date   date NOT NULL
 , start_hour    time
 , end_hour      time
 , expected_hour time
 , tz            text  -- time zone
);

Wie Sie bereits festgestellt haben, timetz (time with time zone ) sollten generell vermieden werden . Es kann nicht richtig mit DST-Regeln umgehen (d aylight s t Zeit).

Also im Grunde das, was Sie bereits hatten . Lassen Sie einfach die Datumskomponente von start_hour weg , das ist tote Fracht. Cast timestamp bis time um das Datum abzuschneiden. Wie:(timestamp '2018-03-25 1:00:00')::time

tz kann jede Zeichenfolge sein, die vom AT TIME ZONE zu konstruieren, aber um zuverlässig mit unterschiedlichen Zeitzonen umzugehen, ist es am besten, ausschließlich Zeitzonennamen zu verwenden. Beliebiger name finden Sie im Systemkatalog pg_timezone_names .

Um die Speicherung zu optimieren, könnten Sie zulässige Zeitzonennamen in einer kleinen Nachschlagetabelle sammeln und tz text ersetzen mit tz_id int REFERENCES my_tz_table .

Zwei Beispielzeilen mit und ohne DST:

INSERT INTO legacy_table VALUES
   (1, '2018-03-25', '1:00', '3:00', '2:00', 'Europe/Vienna')  -- sadly, with DST
 , (2, '2018-03-25', '1:00', '3:00', '2:00', 'Europe/Moscow'); -- Russians got rid of DST

Für Darstellungszwecke oder Berechnungen können Sie Dinge tun wie:

SELECT (report_date + start_hour)    AT TIME ZONE tz AT TIME ZONE 'UTC' AS start_utc
     , (report_date + end_hour)      AT TIME ZONE tz AT TIME ZONE 'UTC' AS end_utc
     , (report_date + expected_hour) AT TIME ZONE tz AT TIME ZONE 'UTC' AS expected_utc
     -- START_HOUR - END_HOUR
     , (report_date + start_hour) AT TIME ZONE tz
     - (report_date + end_hour)   AT TIME ZONE tz AS start_minus_end
FROM   legacy_table;

Sie können eine oder mehrere Ansichten erstellen um Strings nach Bedarf einfach anzuzeigen. Die Tabelle dient zum Speichern der Informationen, die Sie benötigen .

Beachten Sie die Klammern! Sonst der Operator + würde vor AT TIME ZONE binden aufgrund von Operatorpriorität .

Und sehen Sie sich die Ergebnisse an:

db<>fiddle hier

Da die Zeit in Wien manipuliert wird (wie überall dort, wo dumme DST-Regeln gelten), erhalten Sie "überraschende" Ergebnisse.

Verwandte: