W postgresie timestamp with time zone
można go skrócić jako timestamptz
i timestamp without time zone
jako timestamp
. Dla uproszczenia użyję krótszych nazw typów.
Pobieranie uniksowego znacznika czasu z postgres timestamptz
jak now()
jest proste, jak mówisz, po prostu:
select extract(epoch from now());
To naprawdę wszystko, co musisz wiedzieć o uzyskiwaniu czasu bezwzględnego z dowolnego rodzaju timestamptz
, w tym now()
.
Sprawy komplikują się tylko wtedy, gdy masz timestamp
pole.
Kiedy umieścisz timestamptz
dane jak now()
w tym polu, najpierw zostaną one przekonwertowane na określoną strefę czasową (jawnie z at time zone
lub poprzez konwersję do strefy czasowej sesji), a informacja o strefie czasowej zostanie odrzucona . Nie odnosi się już do czasu absolutnego. Dlatego zwykle nie chcesz przechowywać znaczników czasu, timestamp
których normalnie używasz timestamptz
- być może film zostanie wypuszczony o 18:00 w określonym dniu w każdej strefie czasowej , jest to przypadek użycia.
Jeśli kiedykolwiek pracujesz tylko w jednej strefie czasowej, możesz uniknąć (niewłaściwego) używania timestamp
. Konwersja z powrotem do timestamptz
jest wystarczająco sprytna, aby poradzić sobie z czasem letnim, a do celów konwersji zakłada się, że znaczniki czasu znajdują się w bieżącej strefie czasowej. Oto przykład dla GMT / BST:
select '2011-03-27 00:59:00.0+00'::timestamptz::timestamp::timestamptz
, '2011-03-27 01:00:00.0+00'::timestamptz::timestamp::timestamptz;
/*
|timestamptz |timestamptz |
|:---------------------|:---------------------|
|2011-03-27 00:59:00+00|2011-03-27 02:00:00+01|
*/
DBFiddle
Zwróć jednak uwagę na następujące mylące zachowanie:
set timezone to 0;
values(1, '1970-01-01 00:00:00+00'::timestamp::timestamptz)
, (2, '1970-01-01 00:00:00+02'::timestamp::timestamptz);
/*
|column1|column2 |
|------:|:---------------------|
| 1|1970-01-01 00:00:00+00|
| 2|1970-01-01 00:00:00+00|
*/
DBFiddle
Jest tak, ponieważ :
PostgreSQL nigdy nie bada zawartości ciągu literalnego przed określeniem jego typu, dlatego też traktuje zarówno […] jak znacznik czasu bez strefy czasowej. Aby mieć pewność, że literał jest traktowany jako znacznik czasu ze strefą czasową, nadaj mu poprawny jawny typ… W literale, który został określony jako znacznik czasu bez strefy czasowej, PostgreSQL po cichu zignoruje wszelkie wskazania strefy czasowej
SELECT FLOOR(EXTRACT(epoch FROM NOW())*1000);
nie zwraca poprawnego znacznika czasu, ponieważ konwersja strefy czasowej postgres odrzuca informacje o strefie czasowej z wyniku:
następnie wyodrębnia patrzy na znacznik czasu bez strefy czasowej i uznaje go za czas lokalny (chociaż tak naprawdę jest to utc).
Prawidłowy sposób to:
W ostatniej linii pierwsza
at time zone
wykonuje konwersję, druga przypisuje nową strefę czasową do wyniku.źródło