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.