Laat me de twee voorbeelden uitleggen:
In beide gaan we uit van een tijdzone UTC (d.w.z. SET timezone TO UTC
).
db=# SELECT timezone('US/Pacific', '2016-01-01 00:00');
timezone
---------------------
2015-12-31 16:00:00
(1 row)
Dit komt overeen met SELECT timezone('US/Pacific', '2016-01-01 00:00'::timestamptz)
, d.w.z. Postgres heeft de string impliciet geconverteerd naar een timestamptz
.
We weten dat de timezone
functie converteert heen en weer tussen timestamp
en timestamptz
:
Omdat we het een timestamptz
geven als invoer zal het een timestamp
uitvoeren . Met andere woorden, het converteert het absolute tijdstip 2016-01-01 00:00Z
naar een muurtijd in US/Pacific
, d.w.z. wat de klok in Los Angeles op dat absolute tijdstip liet zien.
In voorbeeld 2 doen we het tegenovergestelde, namelijk het nemen van een timestamp
en het converteren naar een timestamptz
. Met andere woorden, we vragen:wat was het absolute tijdstip waarop de klok in Los Angeles 2016-01-01 00:00
aangaf ?
U vermeldt:
'2016-01-01 00:00'::timestamp
is een timestamp
, d.w.z. een muurtijd. Het heeft geen notie van tijdzone.
Ik denk dat je het verschil tussen timestamp
misschien niet helemaal hebt begrepen en timestamptz
, wat hier de sleutel is. Zie ze maar als muurtijd , d.w.z. de tijd die ergens in de wereld werd weergegeven op een klok die aan de muur hing, en absolute tijd , d.w.z. de absolute tijd in ons universum.
De voorbeelden die u in uw eigen antwoord maakt, zijn niet helemaal nauwkeurig.
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);
Het probleem met uw voorbeeld is dat u één gegevensset maakt met een enkele kolom. Aangezien een kolom maar één type kan hebben, wordt elke rij (of enkele waarde in dit geval) geconverteerd naar hetzelfde type, namelijk timestamptz
, ook al zijn sommige waarden berekend als timestamp
(bijv. waarde 3). Je hebt hier dus een extra impliciete conversie.
Laten we het voorbeeld opsplitsen in afzonderlijke zoekopdrachten en kijken wat er aan de hand is:
Voorbeeld 1
db=# SELECT timestamptz '2012-03-05 17:00:00+0';
timestamptz
------------------------
2012-03-05 17:00:00+00
Zoals je misschien al weet, timestamptz '2012-03-05 17:00:00+0'
en '2012-03-05 17:00:00+0'::timestamptz
gelijkwaardig zijn (ik geef de voorkeur aan het laatste). Dus, om dezelfde syntaxis te gebruiken als in het artikel, zal ik herschrijven:
db=# SELECT '2012-03-05 17:00:00+0'::timestamptz;
timestamptz
------------------------
2012-03-05 17:00:00+00
Wat is hier aan de hand? Nou ja, minder dan in je oorspronkelijke uitleg. De string wordt eenvoudig geparseerd als een timestamptz
. Wanneer het resultaat wordt afgedrukt, gebruikt het de momenteel ingestelde timezone
config om het terug te converteren naar een voor mensen leesbare weergave van de onderliggende gegevensstructuur, d.w.z. 2012-03-05 17:00:00+00
.
Laten we de timezone
wijzigen config en kijk wat er gebeurt:
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
Het enige dat is veranderd, is hoe de timestamptz
wordt afgedrukt op het scherm, namelijk met behulp van de Europe/Berlin tijdzone.
Voorbeeld 2
db=# SELECT timestamptz '2012-03-05 18:00:00+1';
timestamptz
------------------------
2012-03-05 17:00:00+00
(1 row)
Nogmaals, even de datum ontleden.
Voorbeeld 3
db=# SELECT timestamp '2012-03-05 18:00:00+1';
timestamp
---------------------
2012-03-05 18:00:00
(1 row)
Dit is hetzelfde als '2012-03-05 18:00:00+1'::timestamp
. Wat hier gebeurt, is dat de tijdzone-offset gewoon wordt genegeerd omdat je om een timestamp
vraagt. .
Voorbeeld 4
db=# SELECT timestamp '2012-03-05 11:00:00' AT TIME ZONE '+6';
timezone
------------------------
2012-03-05 17:00:00+00
(1 row)
Laten we herschrijven om het eenvoudiger te maken:
db=# SELECT timezone('+6', '2012-03-05 11:00:00'::timestamp);
timezone
------------------------
2012-03-05 17:00:00+00
(1 row)
Dit is de vraag:wat was de absolute tijd toen de klok aan de muur in de tijdzone met een offset van +6 uur 2012-03-05 11:00:00
aangaf ?
Voorbeeld 5
db=# SELECT timestamp '2012-03-05 17:00:00' AT TIME ZONE 'UTC';
timezone
------------------------
2012-03-05 17:00:00+00
(1 row)
Laten we herschrijven:
db=# SELECT timezone('UTC', '2012-03-05 17:00:00'::timestamp);
timezone
------------------------
2012-03-05 17:00:00+00
(1 row)
Dit is de vraag:wat was de absolute tijd toen de klok aan de muur in de tijdzone UTC 2012-03-05 17:00:00
aangaf ?
Voorbeeld 6
db=# SELECT timestamp '2012-03-05 17:00:00'::timestamp;
timestamp
---------------------
2012-03-05 17:00:00
(1 row)
Hier cast je twee keer naar timestamp
, wat geen verschil maakt. Laten we vereenvoudigen:
db=# SELECT '2012-03-05 17:00:00'::timestamp;
timestamp
---------------------
2012-03-05 17:00:00
(1 row)
Dat is duidelijk denk ik.
Voorbeeld 7
db=# SELECT timestamp '2012-03-05 17:00:00'::timestamptz;
timestamptz
------------------------
2012-03-05 17:00:00+00
(1 row)
Laten we herschrijven:
db=# SELECT ('2012-03-05 17:00:00'::timestamp)::timestamptz;
timestamptz
------------------------
2012-03-05 17:00:00+00
(1 row)
Je analyseert de string eerst als een timestamp
en vervolgens converteren naar een timestamptz
met de momenteel ingestelde timezone
. Als we de timezone
wijzigen , krijgen we iets anders omdat Postgres die tijdzone aanneemt bij het converteren van een timestamp
(of een string zonder tijdzone-informatie) naar 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)
Deze absolute tijd, uitgedrukt in UTC, is 2012-03-05 16:00:00+00
, dus anders dan het originele voorbeeld.
Ik hoop dat dit de zaken verduidelijkt. Nogmaals, het verschil begrijpen tussen timestamp
en timestamptz
is essentieel. Denk aan muurtijd versus absolute tijd.