sql >> Databasteknik >  >> RDS >> PostgreSQL

Hantera TIME WITH TIME ZONE korrekt i PostgreSQL

Du påstod att:

Så du aldrig korsa en datumlinje inom samma rad. Jag föreslår att du sparar 1x date 3x time och tidszonen (som text eller FK-kolumnen):

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
);

Som du redan hittat, timetz (time with time zone ) bör i allmänhet undvikas . Den kan inte hantera sommartidsreglerna ordentligt (d aylight s aving t ime).

i princip vad du redan hade . Släpp bara datumkomponenten från start_hour , det är dödfrakt. Cast timestamp till time att klippa av datumet. Gilla:(timestamp '2018-03-25 1:00:00')::time

tz kan vara vilken sträng som helst som accepteras av AT TIME ZONE konstruera, men för att hantera olika tidszoner på ett tillförlitligt sätt är det bäst att uteslutande använda tidszonsnamn. Alla name hittar du i systemkatalogen pg_timezone_names .

För att optimera lagringen kan du samla tillåtna tidszonnamn i en liten uppslagstabell och ersätta tz text med tz_id int REFERENCES my_tz_table .

Två exempelrader med och utan sommartid:

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 representationsändamål eller beräkningar kan du göra saker som:

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;

Du kan skapa en eller flera vyer för att enkelt visa strängar vid behov. Tabellen är till för att lagra den information du behöver .

Notera parentesen! Annars operatorn + skulle binda före AT TIME ZONE på grund av operatörsföreträde .

Och se resultatet:

db<>fiol här

Eftersom tiden är manipulerad i Wien (som alla platser där dumma sommarregler gäller) får du "överraskande" resultat.

Relaterat:




  1. Visar en JSON-datauppsättning som en tabell med Node.js och Express

  2. Hur får man ett Shell-skript att fortsätta efter omstart?

  3. Uppdatera ett kolumnvärde och ersätt en del av en sträng

  4. Hur tar man bort från select i MySQL?