Uniksowy znacznik czasu to liczba sekund od północy czasu UTC 1 stycznia 1970 r.
Jak uzyskać poprawną sygnaturę czasową unixa z PostgreSQL?
Porównując z currenttimestamp.com i timestamp.1e5b.de Nie otrzymuję oczekiwanego czasu z PostgreSQL:
Zwraca prawidłowy znacznik czasu:
SELECT extract(epoch from now());
Chociaż to nie „t:
SELECT extract(epoch from now() at time zone "utc");
Mieszkam w strefie czasowej UTC +02. Jaki jest prawidłowy sposób uzyskania aktualnej sygnatury czasowej unixa z PostgreSQL?
Zwraca to poprawny czas i strefę czasową:
SELECT now(); now ------------------------------- 2011-05-18 10:34:10.820464+02
Inny porównanie:
select now(), extract(epoch from now()), extract(epoch from now() at time zone "utc"); now | date_part | date_part -------------------------------+------------------+------------------ 2011-05-18 10:38:16.439332+02 | 1305707896.43933 | 1305700696.43933 (1 row) Unix timestamp from the web sites: 1305707967
Odpowiedź
W postgres, timestamp with time zone
można skrócić jako timestamptz
, a 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ć, aby uzyskać absolutny czas z czegokolwiek typu timestamptz
, w tym now()
.
Sprawy komplikują się tylko wtedy, gdy masz pole timestamp
.
Kiedy umieścisz timestamptz
dane, takie jak now()
w tym polu, zostaną one najpierw przekonwertowane na określoną strefę czasową (jawnie za pomocą at time zone
lub przez konwersję na strefę czasową sesji), a informacje o strefie czasowej są odrzucane . Nie odnosi się już do czasu bezwzględnego. Dlatego zwykle nie chcesz przechowywać sygnatur czasowych jako timestamp
i normalnie używasz timestamptz
– być może film zostanie wydany o 18:00 w określonym data w każdej strefie czasowej , to jest rodzaj przypadku użycia.
Jeśli pracujesz tylko w jednej strefie czasowej, możesz uciec z (niewłaściwym) użyciem 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| */
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| */
PostgreSQL nigdy nie sprawdza zawartości literału przed określeniem jego typu, dlatego traktuje oba […] jako znacznik czasu bez strefy czasowej. Aby upewnij się, że literał jest traktowany jako znacznik czasu ze strefą czasową, nadaj mu poprawny jawny typ… W przypadku literału, który został określony jako znacznik czasu bez strefy czasowej, PostgreSQL po cichu zignoruje wszelkie wskazania strefy czasowej
Komentarze
- Każdy pomysł, jak zamienić wynikowy numer dziesiętny na liczbę całkowitą bez separatora dziesiętnego (mam na myśli połączenie liczby i dziesiętnej jako jedna duża liczba całkowita). Dzięki.
- Na przykład to , ale ' na pewno nie ' naprawdę nie chcę tego robić. Może chcesz pomnożyć przez potęgę dziesięciu i usunąć pozostałe cyfry po przecinku?
- @ W.M. Może tak?
SELECT FLOOR(EXTRACT(epoch FROM NOW())*1000);
Odpowiedź
SELECT extract(epoch from now() at time zone "utc");
nie zwraca poprawnej sygnatury czasowej, ponieważ konwersja strefy czasowej postgres odrzuca informacje o strefie czasowej z wyniku:
9.9.3. W STREFIE CZASOWEJ
Składnia: znacznik czasu bez strefy czasowej AT TIME ZONE zone
Zwraca: timestamp ze strefą czasową
Traktuj dany znacznik czasu bez strefy czasowej jako znajdujący się w określonej strefie czasowejSkładnia: znacznik czasu ze strefą czasową AT TIME ZONE zone
Zwraca: timestamp bez strefy czasowej
Konwertuj podany znacznik czasu ze strefą czasową na nową strefę czasową bez oznaczenia strefy czasowej
następnie extract sprawdza datownik bez strefy czasowej i traktuje go jako czas lokalny (chociaż w rzeczywistości jest to już utc).
Poprawny sposób wyglądałoby następująco:
select now(), extract(epoch from now()), -- correct extract(epoch from now() at time zone "utc"), -- incorrect extract(epoch from now() at time zone "utc" at time zone "utc"); -- correct now | date_part | date_part | date_part -------------------------------+------------------+------------------+------------------ 2014-10-14 10:19:23.726908+02 | 1413274763.72691 | 1413267563.72691 | 1413274763.72691 (1 row)
W ostatnim wierszu pierwszy at time zone
przeprowadza konwersję, druga jedna przypisuje wynikowi nową strefę czasową.