sql >> Database >  >> RDS >> PostgreSQL

Converteren tussen tijdzones in Postgres

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.



  1. Oracle opgeslagen procedure

  2. Voorwaarde uit twee kolommen combineren mysql

  3. Entity Framework core - Bevat is hoofdlettergevoelig of niet hoofdlettergevoelig?

  4. Hoe de grootte van de kolom in de mysql-tabel te krijgen