PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Konwersja między strefami czasowymi w Postgres

Pozwólcie, że wyjaśnię te dwa przykłady:

W obu zakładamy strefę czasową UTC (tj. SET timezone TO UTC ).

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

Jest to odpowiednik SELECT timezone('US/Pacific', '2016-01-01 00:00'::timestamptz) , tj. Postgres niejawnie przekonwertował ciąg na timestamptz .

Wiemy, że timezone funkcja konwertuje tam i z powrotem między timestamp i timestamptz :

Ponieważ dajemy mu timestamptz jako dane wejściowe wygeneruje timestamptz . Innymi słowy jest to konwersja bezwzględnego punktu w czasie 2016-01-01 00:00Z do czasu na ścianie w US/Pacific , czyli co zegar w Los Angeles pokazywał w tym absolutnym momencie.

W przykładzie 2 robimy coś przeciwnego, a mianowicie pobieramy timestamptz i przekonwertować go na timestamptz . Innymi słowy, pytamy:jaki był bezwzględny punkt w czasie, kiedy zegar w Los Angeles wskazywał 2016-01-01 00:00 ?

Wspominasz:

'2016-01-01 00:00'::timestamp to timestamptz , czyli czas na ścianie. Nie ma pojęcia o strefie czasowej.

Myślę, że być może nie zrozumiałeś w pełni różnicy między timestamp i timestamptz , co jest tutaj kluczowe. Pomyśl o nich jako o czasie ściennym , czyli czas pokazywany gdzieś na świecie na zegarze wiszącym na ścianie oraz czas bezwzględny , czyli czas absolutny w naszym wszechświecie.

Przykłady, które podajesz we własnej odpowiedzi, nie są do końca dokładne.

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);

Problem z twoim przykładem polega na tym, że konstruujesz jeden zestaw danych z pojedynczą kolumną. Ponieważ kolumna może mieć tylko jeden typ, każdy wiersz (lub pojedyncza wartość w tym przypadku) jest konwertowany na ten sam typ, a mianowicie timestamptz , mimo że niektóre wartości zostały obliczone jako timestamptz (np. wartość 3). W ten sposób masz tutaj dodatkową niejawną konwersję.

Podzielmy przykład na osobne zapytania i zobaczmy, co się dzieje:

Przykład 1

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

Jak być może już wiesz, timestamptz '2012-03-05 17:00:00+0' i '2012-03-05 17:00:00+0'::timestamptz są równoważne (wolę to drugie). Tak więc, aby użyć tej samej składni, co w artykule, przepiszę:

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

Co się tu dzieje? Cóż, mniej niż w twoim pierwotnym wyjaśnieniu. Ciąg jest po prostu analizowany jako timestamptz . Gdy wynik zostanie wydrukowany, używa aktualnie ustawionej timezone config, aby przekonwertować go z powrotem na czytelną dla człowieka reprezentację podstawowej struktury danych, tj. 2012-03-05 17:00:00+00 .

Zmieńmy timezone skonfiguruj i zobacz, co się stanie:

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

Jedyne, co się zmieniło, to jak timestamptz zostaje wydrukowany na ekranie, a mianowicie za pomocą Europa/Berlin strefa czasowa.

Przykład 2

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

Ponownie, po prostu analizuj datę.

Przykład 3

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

To to samo co '2012-03-05 18:00:00+1'::timestamp . Dzieje się tak, że przesunięcie strefy czasowej jest po prostu ignorowane, ponieważ prosisz o timestamptz .

Przykład 4

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

Przepiszmy, aby być prostszym:

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

To jest pytanie:jaki był bezwzględny czas, kiedy zegar na ścianie w strefie czasowej z przesunięciem +6 godzin pokazywał 2012-03-05 11:00:00 ?

Przykład 5

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

Przepiszmy:

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

To jest pytanie:jaki był bezwzględny czas, kiedy zegar na ścianie w strefie czasowej UTC pokazywał 2012-03-05 17:00:00 ?

Przykład 6

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

Tutaj przesyłasz dwa razy do timestamp , co nie ma znaczenia. Uprośćmy:

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

Myślę, że to jasne.

Przykład 7

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

Przepiszmy:

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

Najpierw analizujesz ciąg jako timestamptz a następnie przekonwertować go na timestamptz używając aktualnie ustawionej timezone . Jeśli zmienimy timezone , otrzymujemy coś innego, ponieważ Postgres zakłada tę strefę czasową podczas konwersji timestamp (lub ciąg bez informacji o strefie czasowej) do 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)

Ten czas bezwzględny, wyrażony w UTC, to 2012-03-05 16:00:00+00 , a więc różni się od oryginalnego przykładu.

Mam nadzieję, że to wszystko wyjaśnia. Ponownie, zrozumienie różnicy między timestamp i timestamptz to klucz. Pomyśl o czasie ściany w porównaniu z czasem bezwzględnym.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Postgres zapobiega znacznikowi czasu z konwersją strefy czasowej

  2. Wiele sprzężeń do tego samego stołu

  3. Czy można skondensować klucz podstawowy/numer seryjny?

  4. Jak zignorować znak zapytania jako symbol zastępczy podczas używania PDO z PostgreSQL?

  5. Jak rejestrować dzienne rankingi modelu w Django?