Antworten:
Die Unterschiede werden in der PostgreSQL-Dokumentation für Datums- / Zeittypen behandelt . Ja, die Behandlung von TIME
oder TIMESTAMP
unterscheidet sich zwischen einem WITH TIME ZONE
oder WITHOUT 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
oder WITHOUT TIME ZONE
) des Werts.Hier sind Beispiele für die Kombinationen dieser Faktoren:
foo=> SET TIMEZONE TO 'Japan';
SET
foo=> SELECT '2011-01-01 00:00:00'::TIMESTAMP;
timestamp
---------------------
2011-01-01 00:00:00
(1 row)
foo=> SELECT '2011-01-01 00:00:00'::TIMESTAMP WITH TIME ZONE;
timestamptz
------------------------
2011-01-01 00:00:00+09
(1 row)
foo=> SELECT '2011-01-01 00:00:00+03'::TIMESTAMP;
timestamp
---------------------
2011-01-01 00:00:00
(1 row)
foo=> SELECT '2011-01-01 00:00:00+03'::TIMESTAMP WITH TIME ZONE;
timestamptz
------------------------
2011-01-01 06:00:00+09
(1 row)
foo=> SET TIMEZONE TO 'Australia/Melbourne';
SET
foo=> SELECT '2011-01-01 00:00:00'::TIMESTAMP;
timestamp
---------------------
2011-01-01 00:00:00
(1 row)
foo=> SELECT '2011-01-01 00:00:00'::TIMESTAMP WITH TIME ZONE;
timestamptz
------------------------
2011-01-01 00:00:00+11
(1 row)
foo=> SELECT '2011-01-01 00:00:00+03'::TIMESTAMP;
timestamp
---------------------
2011-01-01 00:00:00
(1 row)
foo=> SELECT '2011-01-01 00:00:00+03'::TIMESTAMP WITH TIME ZONE;
timestamptz
------------------------
2011-01-01 08:00:00+11
(1 row)
timestamp with time zone
und timestamp 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 zu java.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 zu java.time.Instant
(allerdings mit niedrigerer Auflösung), aber mit JDBC und JPA 2.2 sollten Sie es java.time.OffsetDateTime
(oder zu java.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 gespeichert TIMESTAMP 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.)
TIMESTAMP WITH TIME ZONE
als Instant
. Beide repräsentieren einen Punkt auf der Zeitachse in UTC. Instant
wird meiner Meinung nach vorgezogen, OffsetDateTime
da es selbstdokumentierender ist: A TIMESTAMP WITH TIME ZONE
wird immer als UTC aus der Datenbank abgerufen, und a Instant
ist immer in UTC, also eine natürliche Übereinstimmung, während a OffsetDateTime
andere Offsets tragen kann.
OffsetDateTime
der zugeordnete Java-Typ erwähnt. Ich bin mir nicht sicher, ob Instance
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 in TIMESTAMP WITH TIME ZONE
und wenn diese weiter konvertiert WITHOUT 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.
SELECT now(),
now()::timestamp,
now() AT TIME ZONE 'CST',
now()::timestamp AT TIME ZONE 'CST'
Ausgabe:
-[ RECORD 1 ]---------------------------
now | 2018-09-15 17:01:36.399357+03
now | 2018-09-15 17:01:36.399357
timezone | 2018-09-15 08:01:36.399357
timezone | 2018-09-16 02:01:36.399357+03
timestamp
und timestamptz
meinen. timestamptz
bedeutet einen absoluten Zeitpunkt (UTC), während timestamp
bezeichnet wird, was die Uhr in einer bestimmten Zeitzone zeigte. Wenn Sie also timestamptz
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 a timestamp
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 die WITH
vs.- WITHOUT TIME ZONE
Typen bereits verstehen . Es ist also eine merkwürdige Wahl, sie zu erklären. (: ( AT TIME ZONE
konvertiert einen WITH TIME ZONE
Zeitstempel in einen WITHOUT 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