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.