Werden Zeitstempelwerte in PostgreSQL unterschiedlich gespeichert, wenn der Datentyp WITH TIME ZONE
versus ist WITHOUT TIME ZONE
? Können die Unterschiede mit einfachen Testfällen veranschaulicht werden?
postgresql
types
timestamp
timezone
Larsenal
quelle
quelle
Antworten:
Die Unterschiede werden in der PostgreSQL-Dokumentation für Datums- / Zeittypen behandelt . Ja, die Behandlung von
TIME
oderTIMESTAMP
unterscheidet sich zwischen einemWITH TIME ZONE
oderWITHOUT TIME ZONE
. Es hat keinen Einfluss darauf, wie die Werte gespeichert werden. es beeinflusst, wie sie interpretiert werden.Die Auswirkungen von Zeitzonen auf diese Datentypen werden in den Dokumenten speziell behandelt . Der Unterschied ergibt sich aus dem, was das System vernünftigerweise über den Wert wissen kann:
Mit einer Zeitzone als Teil des Werts kann der Wert als lokale Zeit im Client gerendert werden.
Ohne eine Zeitzone als Teil des Werts ist die offensichtliche Standardzeitzone UTC, sodass sie für diese Zeitzone gerendert wird.
Das Verhalten unterscheidet sich in Abhängigkeit von mindestens drei Faktoren:
WITH TIME ZONE
oderWITHOUT TIME ZONE
) des Werts.Hier sind Beispiele für die Kombinationen dieser Faktoren:
quelle
timestamp with time zone
undtimestamp without time zone
in Postgres * keine Zeitzoneninformationen speichern. Sie können dies mit einem Blick auf die Datentyp-Dokumentseite bestätigen: Beide Typen belegen die gleiche Anzahl von Oktetten und verfügen über den gespeicherten Wertebereich, sodass kein Platz zum Speichern von Zeitzoneninformationen vorhanden ist. Der Text der Seite bestätigt dies. Etwas falsch: "ohne tz" bedeutet "Versatz beim Einfügen von Daten ignorieren" und "mit tz" bedeutet "Versatz zum Anpassen an UTC verwenden".Ich versuche es verständlicher zu erklären als die verwiesene PostgreSQL-Dokumentation.
Keine der
TIMESTAMP
Varianten speichert eine Zeitzone (oder einen Versatz), trotz der Namen. Der Unterschied liegt in der Interpretation der gespeicherten Daten (und in der beabsichtigten Anwendung), nicht im Speicherformat selbst:TIMESTAMP WITHOUT TIME ZONE
speichert die lokale Datums- und Uhrzeit (auch bekannt als Wandkalenderdatum und Wanduhrzeit). Die Zeitzone ist nicht angegeben, soweit PostgreSQL dies beurteilen kann (obwohl Ihre Anwendung möglicherweise weiß, was es ist). Daher führt PostgreSQL keine zeitzonenbezogene Konvertierung bei Eingabe oder Ausgabe durch. Wenn der Wert in die Datenbank eingegeben wurde als'2011-07-01 06:30:30'
, egal in welcher Zeitzone Sie ihn später anzeigen, wird immer noch Jahr 2011, Monat 07, Tag 01, 06 Stunden, 30 Minuten und 30 Sekunden (in einem bestimmten Format) angezeigt. Auch jede Offset- oder Zeitzone in der Eingabe angeben wird von PostgreSQL ignoriert, so'2011-07-01 06:30:30+00'
und'2011-07-01 06:30:30+05'
sind die gleichen wie gerade'2011-07-01 06:30:30'
. Für Java-Entwickler: Es ist analog zujava.time.LocalDateTime
.TIMESTAMP WITH TIME ZONE
speichert einen Punkt auf der UTC-Zeitlinie. Wie es aussieht (wie viele Stunden, Minuten usw.), hängt von Ihrer Zeitzone ab, bezieht sich jedoch immer auf denselben "physischen" Moment (wie den Moment eines tatsächlichen physischen Ereignisses). Die Eingabe wird intern in UTC konvertiert und so gespeichert. Dazu muss der Versatz der Eingabe bekannt sein. Wenn die Eingabe keinen expliziten Versatz oder keine Zeitzone (wie'2011-07-01 06:30:30'
) enthält, wird angenommen, dass sie sich in der aktuellen Zeitzone der PostgreSQL-Sitzung befindet, andernfalls wird der explizit angegebene Versatz oder die explizit angegebene Zeitzone verwendet (wie in'2011-07-01 06:30:30+05'
). Die Ausgabe wird in die aktuelle Zeitzone der PostgreSQL-Sitzung konvertiert angezeigt. Für Java-Entwickler: Es ist analog zujava.time.Instant
(allerdings mit niedrigerer Auflösung), aber mit JDBC und JPA 2.2 sollten Sie esjava.time.OffsetDateTime
(oder zujava.util.Date
oder) zuordnenjava.sql.Timestamp
natürlich).Einige sagen, dass beide
TIMESTAMP
Varianten UTC-Datum und Uhrzeit speichern. Irgendwie, aber es ist meiner Meinung nach verwirrend, es so auszudrücken.TIMESTAMP WITHOUT TIME ZONE
wird wie eine gespeichertTIMESTAMP WITH TIME ZONE
, die mit der UTC-Zeitzone gerendert wird und zufällig das gleiche Jahr, den gleichen Monat, den gleichen Tag, die gleichen Stunden, Minuten, Minuten, Sekunden und Mikrosekunden wie in der lokalen Datums- und Uhrzeitangabe angibt. Es soll jedoch nicht den Punkt auf der Zeitlinie darstellen, den die UTC-Interpretation angibt, sondern nur die Art und Weise, wie die lokalen Datums- und Zeitfelder codiert werden. (Es handelt sich um eine Gruppe von Punkten auf der Zeitachse, da die Echtzeitzone nicht UTC ist. Wir wissen nicht, was es ist.)quelle
TIMESTAMP WITH TIME ZONE
alsInstant
. Beide repräsentieren einen Punkt auf der Zeitachse in UTC.Instant
wird meiner Meinung nach vorgezogen,OffsetDateTime
da es selbstdokumentierender ist: ATIMESTAMP WITH TIME ZONE
wird immer als UTC aus der Datenbank abgerufen, und aInstant
ist immer in UTC, also eine natürliche Übereinstimmung, während aOffsetDateTime
andere Offsets tragen kann.OffsetDateTime
der zugeordnete Java-Typ erwähnt. Ich bin mir nicht sicher, obInstance
irgendwo noch inoffiziell unterstützt wird.'2011-07-01 06:30:30+00'
und'2011-07-01 06:30:30+05'
wird ignoriert, aber ich bin in der Lage,insert into test_table (date) values ('2018-03-24T00:00:00-05:00'::timestamptz);
und es wird es korrekt in utc konvertieren. Dabei ist Datum ein Zeitstempel ohne Zeitzone. Ich versuche zu verstehen, was der Hauptwert von Zeitstempel mit Zeitzone ist und habe Probleme.::timestamptz
. Damit konvertieren Sie die Zeichenfolge inTIMESTAMP WITH TIME ZONE
und wenn diese weiter konvertiertWITHOUT TIME ZONE
wird, werden der "Wandkalender" -Tag und die Wanduhrzeit dieses Augenblicks aus Ihrer Sitzungszeitzone (möglicherweise UTC) gespeichert. Es wird immer noch nur ein lokaler Zeitstempel mit nicht angegebenem Versatz (keine Zone) sein.Hier ist ein Beispiel, das helfen sollte. Wenn Sie einen Zeitstempel mit einer Zeitzone haben, können Sie diesen Zeitstempel in eine andere Zeitzone konvertieren. Wenn Sie keine Basiszeitzone haben, wird diese nicht korrekt konvertiert.
Ausgabe:
quelle
timestamp
undtimestamptz
meinen.timestamptz
bedeutet einen absoluten Zeitpunkt (UTC), währendtimestamp
bezeichnet wird, was die Uhr in einer bestimmten Zeitzone zeigte. Wenn Sie alsotimestamptz
in eine Zeitzone konvertieren , fragen Sie sich, was die Uhr zu diesem absoluten Zeitpunkt in New York gezeigt hat? Während Sie beim "Konvertieren" von atimestamp
fragen, was der absolute Zeitpunkt war, an dem die Uhr in New York x zeigte?AT TIME ZONE
Konstrukt ist ein eigener Denksport, auch wenn Sie dieWITH
vs.-WITHOUT TIME ZONE
Typen bereits verstehen . Es ist also eine merkwürdige Wahl, sie zu erklären. (: (AT TIME ZONE
konvertiert einenWITH TIME ZONE
Zeitstempel in einenWITHOUT TIME ZONE
Zeitstempel und umgekehrt ... nicht genau offensichtlich.)now()::timestamp AT TIME ZONE 'CST'
macht keinen Sinn, es sei denn, Sie würden zu welchem Zeitpunkt eine Uhr für die Zone 'CST' die Zeit anzeigen, die Ihre lokale Uhr gerade anzeigt