Verwenden der aktuellen Zeit in UTC als Standardwert in PostgreSQL

172

Ich habe eine Spalte des TIMESTAMP WITHOUT TIME ZONETyps und möchte diese Standardeinstellung auf die aktuelle Zeit in UTC setzen. Das Abrufen der aktuellen Uhrzeit in UTC ist einfach:

postgres=# select now() at time zone 'utc';
          timezone          
----------------------------
 2013-05-17 12:52:51.337466
(1 row)

Wie wird der aktuelle Zeitstempel für eine Spalte verwendet:

postgres=# create temporary table test(id int, ts timestamp without time zone default current_timestamp);
CREATE TABLE
postgres=# insert into test values (1) returning ts;
             ts             
----------------------------
 2013-05-17 14:54:33.072725
(1 row)

Aber das nutzt die Ortszeit. Der Versuch, dies auf UTC zu erzwingen, führt zu einem Syntaxfehler:

postgres=# create temporary table test(id int, ts timestamp without time zone default now() at time zone 'utc');
ERROR:  syntax error at or near "at"
LINE 1: ...int, ts timestamp without time zone default now() at time zo...
Wichert Akkerman
quelle

Antworten:

297

Eine Funktion wird nicht einmal benötigt. Setzen Sie einfach Klammern um den Standardausdruck:

create temporary table test(
    id int, 
    ts timestamp without time zone default (now() at time zone 'utc')
);
Daniel Vérité
quelle
2
Ich kann eine Funktion wie now_utc () sehen, die wirklich leuchtet, wenn ich Abfragen schreibe
misaxi
Dies funktioniert sogar, wenn die Zeit eine Stunde zurückliegt - now () gibt einen Zeitstempel zurück, der den Versatz von UTC kennt.
Clay Lenhart
1
FWIW, Ausführen dieser Abfrage in PostgreSQL 11.5: ALTER TABLE testcase_result ADD COLUMN date_created TIMESTAMP WITHOUT TIME ZONE DEFAULT (NOW() AT TIME ZONE "UTC") NOT NULL;schlägt fehl mit : ERROR: column "UTC" does not exist. Stellen Sie sicher, dass 'utc'alles in Kleinbuchstaben geschrieben ist.
code_dredd
2
Korrektur: Die 'utc'Zeichenfolge muss auch in einfachen Anführungszeichen und nicht in doppelten Anführungszeichen stehen.
code_dredd
55

Noch eine andere Lösung:

timezone('utc', now())
Martti
quelle
26

Wickeln Sie es in eine Funktion:

create function now_utc() returns timestamp as $$
  select now() at time zone 'utc';
$$ language sql;

create temporary table test(
  id int,
  ts timestamp without time zone default now_utc()
);
Denis de Bernardy
quelle
16

Wie wäre es mit

now()::timestamp

Wenn Ihr anderer Zeitstempel keine Zeitzone hat, ergibt diese Besetzung den passenden Typ "Zeitstempel ohne Zeitzone" für die aktuelle Zeit.

Ich würde gerne lesen, was andere über diese Option denken. Ich vertraue immer noch nicht auf mein Verständnis dieses "mit / ohne" Zeitzonenmaterials.

EDIT: Michael Ekokas Kommentar hier hinzufügen, weil er einen wichtigen Punkt verdeutlicht:

Vorbehalt. Die Frage betrifft das Generieren eines Standardzeitstempels in UTC für eine Zeitstempelspalte, in der die Zeitzone nicht gespeichert ist (möglicherweise, weil die Zeitzone nicht gespeichert werden muss, wenn Sie wissen, dass alle Ihre Zeitstempel dieselbe haben). Ihre Lösung besteht darin, einen lokalen Zeitstempel zu generieren (der für die meisten Menschen nicht unbedingt auf UTC eingestellt ist) und ihn als naiven Zeitstempel zu speichern (der seine Zeitzone nicht angibt).

Risadinha
quelle
Es ist ein interessanter Trick, aber er kann zu Verwirrung führen, wenn Sie sich dieses Verhaltens nicht bewusst sind. Die akzeptierte Antwort ist kristallklar in Bezug auf die Aktion und das gewünschte Ergebnis. Das gleiche gilt für die Funktion, aber ich halte mich von Funktionen in DBs fern ....
Frank V
in meiner Option generiert es lokale Datums- und Uhrzeitangaben in db
VelikiiNehochuha
Vorbehalt. Die Frage betrifft das Generieren eines Standardzeitstempels in UTC für eine Zeitstempelspalte, in der die Zeitzone nicht gespeichert ist (möglicherweise, weil die Zeitzone nicht gespeichert werden muss, wenn Sie wissen, dass alle Ihre Zeitstempel dieselbe haben). Ihre Lösung besteht darin, einen lokalen Zeitstempel zu generieren (der für die meisten Menschen nicht unbedingt auf UTC eingestellt ist) und ihn als naiven Zeitstempel zu speichern (der seine Zeitzone nicht angibt).
Michael Ekoka
@MichaelEkoka Ich habe Ihren Kommentar zur Antwort hinzugefügt - bitte bearbeiten Sie ihn, wenn Sie möchten. Sie erklären es sehr deutlich. Vielen Dank!
Risadinha
Warnung : Ein Zeitstempel mit Zeitzonenfeld speichert die Zeitzone entgegen vernünftiger Annahme NICHT. Siehe den folgenden Link und durchsuchen Sie die Seite nach UTC. Bei der Eingabe konvertiert ein Zeitstempel mit Zeitzone den eingehenden Wert in utc und speichert diesen Wert OHNE ZEITZONE ODER OFFSET-INFORMATIONEN . Bei der Ausgabe wird der gespeicherte utc-Wert unter Verwendung der Zeitzone des Clients in eine Ortszeit konvertiert, sofern verfügbar. Bei diesem Typ dreht sich alles um die Wertkonvertierung zur Abfragezeit. Sie sollten dies testen, indem Sie aus einer Zeitzone speichern und aus einer anderen auswählen. postgresql.org/docs/11/datatype-datetime.html
Tom
7

Dies sind 2 äquivalente Lösungen:

(im folgenden Code, sollten Sie ersetzen 'UTC'für Zone und now()für Zeitstempel )

  1. timestamp AT TIME ZONE zone - SQL-Standard-konform
  2. timezone(zone, timestamp) - wohl besser lesbar

Die Funktion Zeitzone (Zone, Zeitstempel) entspricht der SQL-konformen Konstruktzeitstempel-Zone ZEITZONE.


Erläuterung:

  • Zone kann entweder als Textzeichenfolge (z. B. 'UTC') oder als Intervall (z. B. INTERVAL '-08:00') angegeben werden. Hier finden Sie eine Liste aller verfügbaren Zeitzonen
  • Zeitstempel kann ein beliebiger Wert vom Typ Zeitstempel sein
  • now()Gibt einen Wert vom Typ Zeitstempel (genau das, was wir benötigen) mit der angehängten Standardzeitzone Ihrer Datenbank zurück (z 2018-11-11T12:07:22.3+05:00. B. ).
  • timezone('UTC', now())wandelt unsere aktuelle Zeit (vom Typ Zeitstempel mit Zeitzone ) in das zeitzonenlose Äquivalent in um UTC.
    ZB SELECT timestamp with time zone '2020-03-16 15:00:00-05' AT TIME ZONE 'UTC'wird wiederkommen 2020-03-16T20:00:00Z.

Docs: Zeitzone ()

Seen sind
quelle
1
Vielen Dank für die Zusammenfassung dieser Dinge. Ich habe eine Kleinbuchstabenversion verwendet at timezone 'utc'und das hat mit meinem PostgreSQL-Setup nicht funktioniert. Mit Großbuchstaben gelöst Problem
Geradlus_RU
2

Funktion existiert bereits: Zeitzone ('UTC' :: text, now ())

user10259440
quelle