sql >> Database teknologi >  >> RDS >> PostgreSQL

Konvertering mellem tidszoner i Postgres

Lad mig forklare de to eksempler:

I begge antager vi en tidszone UTC (dvs. SET timezone TO UTC ).

db=# SELECT timezone('US/Pacific', '2016-01-01 00:00');
      timezone
---------------------
 2015-12-31 16:00:00
(1 row)

Dette svarer til SELECT timezone('US/Pacific', '2016-01-01 00:00'::timestamptz) , dvs. Postgres konverterede implicit strengen til en timestamptz .

Vi ved, at timezone funktion konverterer frem og tilbage mellem timestamp og timestamptz :

Da vi giver den en timestamptz som input udsender den et timestamp . Med andre ord konverterer den det absolutte tidspunkt 2016-01-01 00:00Z til en vægtid i US/Pacific , altså hvad uret i Los Angeles viste på det absolutte tidspunkt.

I eksempel 2 gør vi det modsatte, nemlig at tage et timestamp og konvertere den til en timestamptz . Med andre ord, vi spørger:hvad var det absolutte tidspunkt, hvor uret i Los Angeles viste 2016-01-01 00:00 ?

Du nævner:

'2016-01-01 00:00'::timestamp er et timestamp , altså en vægtid. Den har ikke en forestilling om tidszone.

Jeg tror, ​​du måske ikke helt har forstået forskellen mellem timestamp og timestamptz , hvilket er nøglen her. Tænk bare på dem som vægtid , altså tiden, der viste et sted i verden på et ur, der hænger på væggen, og absolut tid , altså den absolutte tid i vores univers.

De eksempler, du laver i dit eget svar, er ikke helt præcise.

SELECT ts FROM  (VALUES
(timestamptz '2012-03-05 17:00:00+0') -- outputs 2012-03-05 17:00:00+00 --1
,(timestamptz '2012-03-05 18:00:00+1') -- outputs 2012-03-05 17:00:00+00 --2
,(timestamp   '2012-03-05 18:00:00+1') -- outputs 2012-03-05 18:00:00+00 --3
,(timestamp   '2012-03-05 11:00:00'  AT TIME ZONE '+6') -- outputs 2012-03-05 17:00:00+00 --4
,(timestamp   '2012-03-05 17:00:00'  AT TIME ZONE 'UTC') -- outputs 2012-03-05 17:00:00+00 --5
,(timestamp   '2012-03-05 17:00:00'::timestamp) -- outputs 2012-03-05 17:00:00+00 --6
,(timestamp   '2012-03-05 17:00:00'::timestamptz) -- outputs 2012-03-05 17:00:00+00 --7
    ) t(ts);

Problemet med dit eksempel er, at du konstruerer et datasæt med en enkelt kolonne. Da en kolonne kun kan have én type, bliver hver række (eller enkelt værdi i dette tilfælde) konverteret til den samme type, nemlig timestamptz , selvom nogle værdier blev beregnet som timestamp (f.eks. værdi 3). Du har således en ekstra implicit konvertering her.

Lad os opdele eksemplet i separate forespørgsler og se, hvad der foregår:

Eksempel 1

db=# SELECT timestamptz '2012-03-05 17:00:00+0';
      timestamptz
------------------------
 2012-03-05 17:00:00+00

Som du måske allerede ved, timestamptz '2012-03-05 17:00:00+0' og '2012-03-05 17:00:00+0'::timestamptz er ækvivalente (jeg foretrækker det sidste). Bare for at bruge den samme syntaks som i artiklen, vil jeg omskrive:

db=# SELECT '2012-03-05 17:00:00+0'::timestamptz;
      timestamptz
------------------------
 2012-03-05 17:00:00+00

Hvad sker der nu her? Nå, mindre end i din oprindelige forklaring. Strengen er simpelthen parset som en timestamptz . Når resultatet bliver udskrevet, bruger det den aktuelt indstillede timezone config for at konvertere den tilbage til en menneskelig læsbar repræsentation af den underliggende datastruktur, dvs. 2012-03-05 17:00:00+00 .

Lad os ændre timezone config og se hvad der sker:

db=# SET timezone TO 'Europe/Berlin';
SET
db=# SELECT '2012-03-05 17:00:00+0'::timestamptz;
      timestamptz
------------------------
 2012-03-05 18:00:00+01

Det eneste, der ændrede sig, er hvordan timestamptz bliver udskrevet på skærmen, nemlig ved hjælp af Europa/Berlin tidszone.

Eksempel 2

db=# SELECT timestamptz '2012-03-05 18:00:00+1';
      timestamptz
------------------------
 2012-03-05 17:00:00+00
(1 row)

Igen, bare parsing af datoen.

Eksempel 3

db=# SELECT timestamp '2012-03-05 18:00:00+1';
      timestamp
---------------------
 2012-03-05 18:00:00
(1 row)

Dette er det samme som '2012-03-05 18:00:00+1'::timestamp . Det, der sker her, er, at tidszoneforskydningen simpelthen ignoreres, fordi du beder om et timestamp .

Eksempel 4

db=# SELECT timestamp '2012-03-05 11:00:00' AT TIME ZONE '+6';
        timezone
------------------------
 2012-03-05 17:00:00+00
(1 row)

Lad os omskrive for at være enklere:

db=# SELECT timezone('+6', '2012-03-05 11:00:00'::timestamp);
        timezone
------------------------
 2012-03-05 17:00:00+00
(1 row)

Dette spørger:hvad var det absolutte tidspunkt, da uret på væggen i tidszonen med en offset på +6 timer viste 2012-03-05 11:00:00 ?

Eksempel 5

db=# SELECT timestamp '2012-03-05 17:00:00' AT TIME ZONE 'UTC';
        timezone
------------------------
 2012-03-05 17:00:00+00
(1 row)

Lad os omskrive:

db=# SELECT timezone('UTC', '2012-03-05 17:00:00'::timestamp);
        timezone
------------------------
 2012-03-05 17:00:00+00
(1 row)

Dette spørger:hvad var det absolutte tidspunkt, da uret på væggen i tidszonen UTC viste 2012-03-05 17:00:00 ?

Eksempel 6

db=# SELECT timestamp '2012-03-05 17:00:00'::timestamp;
      timestamp
---------------------
 2012-03-05 17:00:00
(1 row)

Her caster du to gange til timestamp , hvilket ikke gør nogen forskel. Lad os forenkle:

db=# SELECT '2012-03-05 17:00:00'::timestamp;
      timestamp
---------------------
 2012-03-05 17:00:00
(1 row)

Det er klart, synes jeg.

Eksempel 7

db=# SELECT timestamp '2012-03-05 17:00:00'::timestamptz;
      timestamptz
------------------------
 2012-03-05 17:00:00+00
(1 row)

Lad os omskrive:

db=# SELECT ('2012-03-05 17:00:00'::timestamp)::timestamptz;
      timestamptz
------------------------
 2012-03-05 17:00:00+00
(1 row)

Du parser først strengen som et timestamp og derefter konvertere den til en timestamptz ved at bruge den aktuelt indstillede timezone . Hvis vi ændrer timezone , får vi noget andet, fordi Postgres antager den tidszone, når den konverterer et timestamp (eller en streng, der mangler tidszoneoplysninger) til timestamptz :

db=# SET timezone TO 'Europe/Berlin';
SET
db=# SELECT ('2012-03-05 17:00:00'::timestamp)::timestamptz;
      timestamptz
------------------------
 2012-03-05 17:00:00+01
(1 row)

Denne absolutte tid, udtrykt i UTC, er 2012-03-05 16:00:00+00 , således forskellig fra det oprindelige eksempel.

Jeg håber, at dette afklarer tingene. Igen, at forstå forskellen mellem timestamp og timestamptz er nøglen. Tænk på vægtid versus absolut tid.



  1. JDBC-forbindelsestimeout kan ikke oprette forbindelse igen

  2. CloudSQL PDO(unix_socket) problemer på Google App Engine

  3. MySQL Workbench-rapporter er ikke gyldige på denne position for denne serverversionsfejl

  4. Bash Script til at installere PostgreSQL - Virker ikke