PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Gérer correctement TIME WITH TIME ZONE dans PostgreSQL

Vous avez affirmé que :

Alors vous jamais franchir la ligne de date dans la même ligne. Je suggère de sauvegarder 1x date 3x time et le fuseau horaire (comme text ou colonne FK) :

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

Comme vous l'avez déjà trouvé, timetz (time with time zone ) devrait généralement être évitée . Il ne peut pas gérer correctement les règles DST (d allumer des s en économisant t temps).

Donc essentiellement ce que vous aviez déjà . Déposez simplement le composant de date de start_hour , c'est du fret mort. Diffuser timestamp à time pour couper la date. Comme :(timestamp '2018-03-25 1:00:00')::time

tz peut être n'importe quelle chaîne acceptée par AT TIME ZONE construire, mais pour gérer différents fuseaux horaires de manière fiable, il est préférable d'utiliser exclusivement des noms de fuseaux horaires. N'importe quel name vous trouvez dans le catalogue système pg_timezone_names .

Pour optimiser le stockage, vous pouvez collecter les noms de fuseaux horaires autorisés dans une petite table de recherche et remplacer le tz text avec tz_id int REFERENCES my_tz_table .

Deux exemples de lignes avec et sans 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

À des fins de représentation ou de calculs, vous pouvez faire des choses comme :

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;

Vous pouvez créer une ou plusieurs vues pour afficher facilement les chaînes selon les besoins. Le tableau sert à stocker les informations dont vous avez besoin .

Attention aux parenthèses ! Sinon l'opérateur + se lierait avant AT TIME ZONE en raison de la priorité des opérateurs .

Et voici les résultats :

db<>violon ici

Étant donné que l'heure est manipulée à Vienne (comme n'importe quel endroit où s'appliquent des règles stupides d'heure d'été), vous obtenez des résultats "surprenants".

Connexe :