Wie erhalte ich den aktuellen Unix-Zeitstempel von PostgreSQL?

91

Der Unix-Zeitstempel gibt die Anzahl der Sekunden seit Mitternacht UTC am 1. Januar 1970 an.

Wie erhalte ich den richtigen Unix-Zeitstempel von PostgreSQL?

Beim Vergleich mit currenttimestamp.com und timestamp.1e5b.de erhalte ich nicht die erwartete Zeit von PostgreSQL:

Dies gibt den korrekten Zeitstempel zurück:

SELECT extract(epoch from now());

Während dies nicht der Fall ist:

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

Ich lebe in der Zeitzone UTC +02. Was ist der richtige Weg, um den aktuellen Unix-Zeitstempel von PostgreSQL zu erhalten?

Dies gibt die richtige Zeit und Zeitzone zurück:

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

Ein weiterer Vergleich:

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
Jonas
quelle

Antworten:

82

In postgres timestamp with time zonekann als timestamptzund timestamp without time zoneals abgekürzt werden timestamp. Ich werde der Einfachheit halber die kürzeren Typnamen verwenden.

Erster den Unix - Zeitstempel von einem Postgres timestamptzwie now()einfach ist, wie Sie sagen, nur:

select extract(epoch from now());

Das ist wirklich alles, was Sie wissen müssen, um die absolute Zeit von jedem Typ zu erhalten timestamptz, einschließlich now().

Kompliziert wird es erst, wenn man ein timestampFeld hat.

Wenn Sie timestamptzDaten wie diese now()in dieses Feld einfügen, werden sie zuerst in eine bestimmte Zeitzone konvertiert (entweder explizit mit at time zoneoder durch Konvertieren in die Sitzungszeitzone) und die Zeitzoneninformationen werden verworfen . Es bezieht sich nicht mehr auf eine absolute Zeit. Aus diesem Grund möchten Sie Zeitstempel timestampnormalerweise nicht so speichern, wie sie normalerweise verwendet werden timestamptz- möglicherweise wird ein Film um 18:00 Uhr an einem bestimmten Datum in jeder Zeitzone veröffentlicht. Dies ist die Art von Anwendungsfall.

Wenn Sie immer nur in einer einzigen Zeitzone arbeiten, können Sie (Fehl-) Gebrauch machen timestamp. Die Konvertierung zurück nach timestamptzist klug genug, um mit der Sommerzeit fertig zu werden, und für Konvertierungszwecke wird angenommen, dass die Zeitstempel in der aktuellen Zeitzone liegen. Hier ist ein Beispiel für 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

Beachten Sie jedoch das folgende verwirrende Verhalten:

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

Das liegt daran, dass :

PostgreSQL untersucht niemals den Inhalt eines Literalstrings, bevor sein Typ bestimmt wird, und behandelt daher beide […] als Zeitstempel ohne Zeitzone. Um sicherzustellen, dass ein Literal als Zeitstempel mit Zeitzone behandelt wird, geben Sie ihm den richtigen expliziten Typ ... In einem Literal, das als Zeitstempel ohne Zeitzone festgelegt wurde, ignoriert PostgreSQL jede Zeitzonenangabe unbemerkt

Jack Douglas
quelle
Irgendeine Idee, wie man die resultierende Dezimalzahl in eine Ganzzahl ohne Dezimalpunkt umwandelt (ich meine, die Zahl und die Dezimalzahl als eine große Ganzzahl zusammenführen). Vielen Dank.
WM
Wie dies aber ich bin sicher , dass Sie nicht möchten , dass nicht wirklich tun. Vielleicht möchten Sie mit einer Zehnerpotenz multiplizieren und alle verbleibenden Dezimalstellen entfernen?
Jack Douglas
2
@WM Vielleicht so? SELECT FLOOR(EXTRACT(epoch FROM NOW())*1000);
Joe23
21
SELECT extract(epoch from now() at time zone 'utc');

gibt nicht den korrekten Zeitstempel zurück, da nach der Konvertierung der Zeitzone die Zeitzoneninformationen aus dem Ergebnis entfernt werden:

9.9.3. Zur Zeitzone

Syntax: Zeitstempel ohne Zeitzone AT TIME ZONE zone
Rückgabe: Zeitstempel mit Zeitzone
Behandelt den angegebenen Zeitstempel ohne Zeitzone so, wie er sich in der angegebenen Zeitzone befindet

Syntax: Zeitstempel mit Zeitzone AT TIME ZONE zone
Rückgabe: Zeitstempel ohne Zeitzone
Konvertiert den angegebenen Zeitstempel mit Zeitzone in die neue Zeitzone ohne Zeitzonenangabe

Anschließend betrachtet extract den Zeitstempel ohne Zeitzone und betrachtet ihn als Ortszeit (obwohl dies bereits utc ist).

Der richtige Weg wäre:

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)

In der letzten Zeile führt die erste at time zonedie Konvertierung durch, die zweite ordnet dem Ergebnis eine neue Zeitzone zu.

axil
quelle