Jak uzyskać aktualny znacznik czasu unixa z PostgreSQL?

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| */ 

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

To jest spowodowane tym, że :

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 czasowej

Skł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ą.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *