sql >> Databasteknik >  >> RDS >> PostgreSQL

Konvertera mellan tidszoner i Postgres

Låt mig förklara de två exemplen:

I båda antar vi en tidszon 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)

Detta motsvarar SELECT timezone('US/Pacific', '2016-01-01 00:00'::timestamptz) , dvs. Postgres konverterade implicit strängen till en timestamptz .

Vi vet att timezone funktion konverterar fram och tillbaka mellan timestamp och timestamptz :

Eftersom vi ger den en timestamptz som indata matas den ut en timestamp . Med andra ord, den konverterar den absoluta tidpunkten 2016-01-01 00:00Z till en väggtid i US/Pacific , det vill säga vad klockan i Los Angeles visade vid den absoluta tidpunkten.

I exempel 2 gör vi tvärtom, nämligen att ta en timestamp och konvertera den till en timestamptz . Med andra ord, vi frågar:vad var den absoluta tidpunkten när klockan i Los Angeles visade 2016-01-01 00:00 ?

Du nämner:

'2016-01-01 00:00'::timestamp är en timestamp , alltså en väggtid. Den har ingen uppfattning om tidszon.

Jag tror att du kanske inte helt har förstått skillnaden mellan timestamp och timestamptz , vilket är nyckeln här. Tänk bara på dem som väggtid , dvs tiden som visade någonstans i världen på en klocka som hängde på väggen, och absolut tid , det vill säga den absoluta tiden i vårt universum.

Exemplen du gör i ditt eget svar är inte helt korrekta.

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 ditt exempel är att du konstruerar en datamängd med en enda kolumn. Eftersom en kolumn bara kan ha en typ, konverteras varje rad (eller enstaka värde i detta fall) till samma typ, nämligen timestamptz , även om vissa värden beräknades som timestamp (t.ex. värde 3). Du har alltså en ytterligare implicit konvertering här.

Låt oss dela upp exemplet i separata frågor och se vad som händer:

Exempel 1

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

Som du kanske redan vet, timestamptz '2012-03-05 17:00:00+0' och '2012-03-05 17:00:00+0'::timestamptz är likvärdiga (jag föredrar det senare). Därför, bara för att använda samma syntax som i artikeln, kommer jag att skriva om:

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

Nu, vad händer här? Tja, mindre än i din ursprungliga förklaring. Strängen tolkas helt enkelt som en timestamptz . När resultatet skrivs ut använder det den för närvarande inställda timezone config för att konvertera den tillbaka till en mänsklig läsbar representation av den underliggande datastrukturen, dvs. 2012-03-05 17:00:00+00 .

Låt oss ändra timezone config och se vad som händer:

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 enda som ändrades är hur timestamptz skrivs ut på skärmen, nämligen med hjälp av Europa/Berlin tidszon.

Exempel 2

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

Återigen, bara analysera datumet.

Exempel 3

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

Detta är samma som '2012-03-05 18:00:00+1'::timestamp . Vad som händer här är att tidszonsförskjutningen helt enkelt ignoreras eftersom du ber om en timestamp .

Exempel 4

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

Låt oss skriva om för att vara enklare:

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

Detta frågar:vad var den absoluta tiden när klockan på väggen i tidszonen med en offset på +6 timmar visade 2012-03-05 11:00:00 ?

Exempel 5

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

Låt oss skriva om:

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

Detta frågar:vad var den absoluta tiden när klockan på väggen i tidszonen UTC visade 2012-03-05 17:00:00 ?

Exempel 6

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

Här castar du två gånger till timestamp , vilket inte gör någon skillnad. Låt oss förenkla:

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

Det är klart tycker jag.

Exempel 7

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

Låt oss skriva om:

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

Du analyserar först strängen som en timestamp och sedan konvertera den till en timestamptz med den för närvarande inställda timezone . Om vi ​​ändrar timezone , får vi något annat eftersom Postgres antar den tidszonen när vi konverterar en timestamp (eller en sträng som saknar tidszoninformation) till 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)

Denna absoluta tid, uttryckt i UTC, är 2012-03-05 16:00:00+00 , alltså annorlunda än det ursprungliga exemplet.

Jag hoppas att detta klargör saker och ting. Återigen, att förstå skillnaden mellan timestamp och timestamptz är nyckeln. Tänk på väggtid kontra absolut tid.



  1. Hantera frysning i PostgreSQL

  2. Vad är SYSNAME-datatyp i SQL Server?

  3. % logga in i Javas PreparedStatement

  4. endast mysqldump-data