Come posso ottenere l'attuale timestamp unix da PostgreSQL?


91

Il timestamp di Unix è il numero di secondi dalla mezzanotte UTC del 1 gennaio 1970.

Come posso ottenere il timestamp unix corretto da PostgreSQL?

Rispetto a currenttimestamp.com e timestamp.1e5b.de non ottengo il tempo previsto da PostgreSQL:

Questo restituisce il timestamp corretto:

SELECT extract(epoch from now());

Anche se questo non:

SELECT extract(epoch from now() at time zone 'utc');

Vivo nel fuso orario UTC +02. Qual è il modo corretto per ottenere l'attuale timestamp unix da PostgreSQL?

Ciò restituisce l'ora e il fuso orario corretti:

SELECT now();
              now
-------------------------------
 2011-05-18 10:34:10.820464+02

Un altro confronto:

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

Risposte:


82

In postgres, timestamp with time zonepuò essere abbreviato come timestamptze timestamp without time zonecome timestamp. Userò i nomi di tipo più brevi per semplicità.

Ottenere il timestamp Unix da un postgres timestamptzcome now()è semplice, come dici tu, solo:

select extract(epoch from now());

Questo è davvero tutto ciò che devi sapere per ottenere il tempo assoluto da qualsiasi cosa di tipo timestamptz, incluso now().

Le cose si complicano solo quando hai un timestampcampo.

Quando si inseriscono timestamptzdati come now()in quel campo, verranno prima convertiti in un determinato fuso orario (esplicitamente con at time zoneo convertendo nel fuso orario della sessione) e le informazioni sul fuso orario vengono scartate . Non si riferisce più a un tempo assoluto. Questo è il motivo per cui di solito non si desidera memorizzare i timestamp come timestampe normalmente si usano timestamptz- forse un film viene rilasciato alle 18:00 in una data particolare in ogni fuso orario , questo è il tipo di caso d'uso.

Se lavori sempre in un solo fuso orario potresti usare (mis) usando timestamp. La conversione a timestamptzè abbastanza intelligente da far fronte all'ora legale e si presume che i timestamp, ai fini della conversione, si trovino nel fuso orario corrente. Ecco un esempio per 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

Tuttavia, nota il seguente comportamento confuso:

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

Questo perché :

PostgreSQL non esamina mai il contenuto di una stringa letterale prima di determinarne il tipo e pertanto tratterà entrambi […] come timestamp senza fuso orario. Per assicurarti che un valore letterale sia trattato come data / ora con fuso orario, dagli il tipo esplicito corretto ... In un valore letterale che è stato determinato come data / ora senza fuso orario, PostgreSQL ignora silenziosamente qualsiasi indicazione di fuso orario


Qualche idea su come convertire il decimale risultante in un numero intero senza punto decimale (intendo unire il numero e il decimale come un intero grande). Grazie.
WM,

In questo modo, ma sono sicuro che non vuoi davvero farlo. Forse vuoi moltiplicare per una potenza di dieci e togliere eventuali decimali rimanenti?
Jack Douglas

2
@WM Forse in questo modo? SELECT FLOOR(EXTRACT(epoch FROM NOW())*1000);
Joe23,

21
SELECT extract(epoch from now() at time zone 'utc');

non restituisce il timestamp corretto perché la conversione del fuso orario di postgres elimina le informazioni sul fuso orario dal risultato:

9.9.3. ALLA FUSO ORARIO

Sintassi: timestamp senza fuso orario FUSO ORARIO Fuso orario
Restituisce: timestamp con fuso orario
Tratta il timestamp dato senza fuso orario come situato nel fuso orario specificato

Sintassi: timestamp con fuso orario FUSO ORARIO Fuso orario
Restituisce: timestamp senza fuso orario
Converti il timestamp dato con fuso orario nel nuovo fuso orario, senza indicazione del fuso orario

in seguito, extract esamina il timestamp senza fuso orario e lo considera come un orario locale (anche se in realtà è già utc).

Il modo corretto sarebbe:

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)

Nell'ultima riga la prima at time zoneesegue la conversione, la seconda assegna un nuovo fuso orario al risultato.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.