TIMESTAMPTZ vs TIMESTAMP: PostgreSQL-Dashboards und APIs
TIMESTAMPTZ vs TIMESTAMP in PostgreSQL: wie die Wahl den Verlauf in Dashboards, API-Antworten, Zeitzonenkonvertierungen und Sommerzeit-Fehler beeinflusst.

Das eigentliche Problem: ein Ereignis, viele Interpretationen
Ein Ereignis passiert einmal, aber es wird auf dutzende Arten berichtet. Die Datenbank speichert einen Wert, eine API serialisiert ihn, ein Dashboard gruppiert ihn, und jede Person sieht ihn in ihrer eigenen Zeitzone. Wenn eine Schicht eine andere Annahme trifft, kann dieselbe Zeile wie zwei verschiedene Zeitpunkte aussehen.
Deshalb ist die Wahl zwischen TIMESTAMPTZ und TIMESTAMP nicht nur eine Datentyp-PrÀferenz. Sie entscheidet, ob ein gespeicherter Wert einen konkreten Moment in der Zeit reprÀsentiert oder eine Wanduhrzeit, die nur an einem bestimmten Ort Sinn ergibt.
Das bricht meistens zuerst: Ein Verkaufsdashboard zeigt unterschiedliche Tageszahlen in New York und Berlin. Ein stĂŒndliches Diagramm hat wĂ€hrend der DST-Ănderung eine fehlende Stunde oder eine doppelte Stunde. Ein Audit-Log wirkt auĂerhalb der Reihenfolge, weil zwei Systeme sich auf das Datum "einigen", aber nicht auf den tatsĂ€chlichen Moment.
Ein einfaches Modell bewahrt dich vor Problemen:
- Speicherung: was du in PostgreSQL speicherst und was es bedeutet.
- Anzeige: wie du es in einer UI, einem Export oder Report formatierst.
- Benutzer-Locale: die Zeitzone und Kalenderregeln des Betrachters, inkl. DST.
Vermischst du diese, entstehen leise Reporting-Fehler. Ein Support-Team exportiert âTickets, die gestern erstellt wurdenâ aus einem Dashboard und vergleicht sie mit einem API-Report. Beides wirkt plausibel, aber eines nutzte die lokale Mitternachtsgrenze des Betrachters, das andere UTC.
Das Ziel ist einfach: FĂŒr jeden Zeitwert zwei klare Entscheidungen treffen. Entscheide, was du speicherst, und entscheide, was du zeigst. Diese Klarheit muss durch dein Datenmodell, API-Antworten und Dashboards durchziehen, damit alle denselben Zeitstrahl sehen.
Was TIMESTAMP und TIMESTAMPTZ tatsÀchlich bedeuten
In PostgreSQL sind die Namen irrefĂŒhrend. Sie wirken, als wĂŒrden sie beschreiben, was gespeichert wird, aber sie beschreiben eher, wie PostgreSQL Eingaben interpretiert und Ausgaben formatiert.
TIMESTAMP (aka timestamp without time zone) ist nur ein Kalenderdatum und eine Uhrzeit, wie 2026-01-29 09:00:00. Es ist keine Zeitzone angehĂ€ngt. PostgreSQL konvertiert diese Werte nicht fĂŒr dich. Zwei Personen in verschiedenen Zeitzonen können denselben TIMESTAMP lesen und unterschiedliche reale Momente annehmen.
TIMESTAMPTZ (aka timestamp with time zone) reprÀsentiert einen echten Punkt in der Zeit. Denk daran als einen Instant. PostgreSQL normalisiert ihn intern (effektiv zu UTC) und zeigt ihn dann in der Zeitzone an, die deine Session verwendet.
Das Verhalten hinter den meisten Ăberraschungen ist:
- Bei Eingabe: PostgreSQL konvertiert
TIMESTAMPTZ-Werte zu einem einheitlichen vergleichbaren Zeitpunkt. - Bei Ausgabe: PostgreSQL formatiert diesen Zeitpunkt mit der aktuellen Session-Zeitzone.
- Bei
TIMESTAMP: es gibt keine automatische Konvertierung bei Ein- oder Ausgabe.
Ein kleines Beispiel zeigt den Unterschied. Angenommen, deine App erhĂ€lt 2026-03-08 02:30 von einem Nutzer. Wenn du das in eine TIMESTAMP-Spalte einfĂŒgst, speichert PostgreSQL exakt diesen Wanduhrwert. Wenn diese lokale Zeit wegen eines DST-Sprungs nicht existiert, merkst du das vielleicht erst, wenn Reports fehlschlagen.
Wenn du in TIMESTAMPTZ einfĂŒgst, braucht PostgreSQL eine Zeitzone, um den Wert zu interpretieren. Gibst du z. B. 2026-03-08 02:30 America/New_York, konvertiert PostgreSQL das in einen Instant (oder wirft je nach Regel und genauem Wert einen Fehler). SpĂ€ter zeigt ein Dashboard in London eine andere lokale Uhrzeit, aber es ist derselbe Instant.
Ein hĂ€ufiger Irrtum: Leute sehen âwith time zoneâ und erwarten, PostgreSQL wĂŒrde das ursprĂŒngliche Zeitzonen-Label speichern. Tut es nicht. PostgreSQL speichert den Moment, nicht das Label. Wenn du die ursprĂŒngliche Zeitzone des Nutzers fĂŒr die Anzeige brauchst (zum Beispiel âzeige es in der lokalen Zeit des Kundenâ), speichere die Zone separat als Textfeld.
Session-Zeitzone: die versteckte Einstellung hinter vielen Ăberraschungen
PostgreSQL hat eine Einstellung, die still beeinflusst, was du siehst: die Session-Zeitzone. Zwei Personen können dieselbe Abfrage auf denselben Daten laufen lassen und unterschiedliche Uhrzeiten zurĂŒckbekommen, weil ihre Sessions verschiedene Zeitzonen verwenden.
Das betrifft hauptsÀchlich TIMESTAMPTZ. PostgreSQL speichert einen absoluten Moment und zeigt ihn dann in der Session-Zeitzone an. Bei TIMESTAMP (ohne Zeitzone) behandelt PostgreSQL den Wert als reine Kalenderzeit. Es verschiebt ihn nicht zur Anzeige, aber die Session-Zeitzone kann dich trotzdem treffen, wenn du ihn in TIMESTAMPTZ konvertierst oder mit zeitzonenbewussten Werten vergleichst.
Session-Zeitzonen werden oft ohne dein Wissen gesetzt: Startkonfiguration der App, Treiber-Parameter, Connection Pools, die alte Sessions wiederverwenden, BI-Tools mit eigenen Defaults, ETL-Jobs, die Server-Locale erben, oder manuelle SQL-Konsolen, die die Einstellungen deines Laptops nutzen.
So streiten Teams oft: Angenommen, ein Ereignis ist in einer TIMESTAMPTZ-Spalte als 2026-03-08 01:30:00+00 gespeichert. Eine Dashboard-Session mit America/Los_Angeles zeigt es als die vorherige lokale Abendzeit an, wÀhrend eine API-Session in UTC eine andere Uhrzeit zeigt. Wenn ein Diagramm nach Tagen gruppiert, wobei das Tages-Bucket session-lokal ist, erhÀltst du unterschiedliche Tageszahlen.
-- Make your output consistent for a reporting job
SET TIME ZONE 'UTC';
SELECT created_at, date_trunc('day', created_at) AS day_bucket
FROM events;
FĂŒr alles, was Reports oder API-Antworten erzeugt, mache die Zeitzone explizit. Setze sie beim Verbinden (oder fĂŒhre zuerst SET TIME ZONE aus), wĂ€hle einen Standard fĂŒr maschinenlesbare Ausgaben (oft UTC), und fĂŒr âlokale GeschĂ€ftszeitâ-Reports setze die GeschĂ€ftszone innerhalb des Jobs, nicht auf dem Laptop von jemandem. Wenn du Connection-Pools nutzt, setze Session-Einstellungen zurĂŒck, wenn eine Verbindung ausgecheckt wird.
Wie Dashboards brechen: Gruppieren, Buckets und DST-LĂŒcken
Dashboards wirken simpel: Bestellungen pro Tag zĂ€hlen, Anmeldungen pro Stunde zeigen, Woche-ĂŒber-Woche vergleichen. Probleme beginnen, wenn die Datenbank einen âMomentâ speichert, das Diagramm ihn aber in viele verschiedene âTageâ verwandelt, abhĂ€ngig davon, wer zusieht.
Wenn du nach Tag in der lokalen Zeitzone eines Nutzers gruppierst, können zwei Personen unterschiedliche Daten fĂŒr dasselbe Ereignis sehen. Eine Bestellung um 23:30 in Los Angeles ist in Berlin bereits âmorgenâ. Und wenn dein SQL mit DATE(created_at) auf einem einfachen TIMESTAMP gruppiert, gruppierst du nicht nach einem echten Moment. Du gruppierst nach einer Wanduhr-Lesung ohne Zeitzonen-Kontext.
StĂŒndliche Diagramme werden um DST herum noch komplizierter. Im FrĂŒhling tritt eine lokale Stunde nicht auf, also zeigen Diagramme eine LĂŒcke. Im Herbst kommt eine Stunde doppelt vor, sodass du einen Spike oder doppelte Buckets bekommst, wenn Abfrage und Dashboard nicht ĂŒbereinstimmen, welche 01:30 gemeint ist.
Eine praktische Frage hilft: Zeigst du echte Momente (die sich sicher konvertieren lassen) oder eine lokale Planungszeit (die nicht konvertiert werden darf)? Dashboards wollen fast immer echte Momente.
Wann nach UTC vs. einer GeschÀftszeitzone gruppieren
WĂ€hle eine Gruppierungsregel und wende sie ĂŒberall an (SQL, API, BI-Tool), sonst driften die Summen auseinander.
Gruppiere nach UTC, wenn du eine globale, konsistente Serie willst (System-Health, API-Traffic, globale Anmeldungen). Gruppiere nach einer GeschĂ€ftszeitzone, wenn âder Tagâ eine rechtliche oder operative Bedeutung hat (Filialtag, Support-SLAs, Finanzabschluss). Gruppiere nach der Zeitzone des Betrachters nur, wenn Personalisierung wichtiger ist als Vergleichbarkeit (persönliche AktivitĂ€tsfeeds).
Das Muster fĂŒr konsistente âGeschĂ€ftstageâ-Gruppierung:
SELECT date_trunc('day', created_at AT TIME ZONE 'America/New_York') AS business_day,
count(*)
FROM orders
GROUP BY 1
ORDER BY 1;
Labels, die Misstrauen verhindern
Menschen verlieren Vertrauen in Charts, wenn Zahlen springen und niemand erklĂ€ren kann, warum. Beschrifte die Regel direkt in der UI: âDaily orders (America/New_York)â oder âHourly events (UTC)â. Verwende dieselbe Regel in Exporten und APIs.
Ein einfacher Regelkatalog fĂŒr Reporting und APIs
Entscheide, ob du einen Instant speicherst oder eine lokale Wanduhrzeit. Das Mischen dieser beiden ist der Punkt, an dem Dashboards und APIs anfangen, sich zu unterscheiden.
Ein Regelset, das Reporting vorhersagbar macht:
- Speichere realweltliche Ereignisse als Instants mit
TIMESTAMPTZund behandle UTC als Quelle der Wahrheit. - Speichere GeschĂ€ftsbegriffe wie âAbrechnungsdatumâ getrennt als
DATE(oder ein Lokalzeit-Feld, wenn du wirklich die Wanduhrzeit brauchst). - Gib in APIs Timestamps in ISO 8601 zurĂŒck und sei konsistent: immer einen Offset (wie
+02:00) einschlieĂen oder immerZfĂŒr UTC verwenden. - Konvertiere an den RĂ€ndern (UI und Reporting-Layer). Vermeide Konvertationen hin und her innerhalb von Datenbank-Logik und Hintergrundjobs.
Warum das standhÀlt: Dashboards bucketen und vergleichen Bereiche. Wenn du Instants (TIMESTAMPTZ) speicherst, kann PostgreSQL Ereignisse zuverlÀssig ordnen und filtern, selbst wenn DST verschiebt. Dann entscheidest du, wie du sie anzeigst oder gruppierst. Wenn du eine lokale Wanduhrzeit (TIMESTAMP) ohne Zeitzone speicherst, kann PostgreSQL nicht wissen, was sie bedeutet, also kann Gruppieren Àndern, wenn sich die Session-Zeitzone Àndert.
Halte âlokale GeschĂ€ftsdatenâ getrennt, weil sie keine Instants sind. âLiefern am 2026-03-08â ist eine Datumsentscheidung, kein Moment. Wenn du das in einen Timestamp quetschst, können DST-Tage fehlende oder doppelte lokale Stunden erzeugen, die spĂ€ter als LĂŒcken oder Spitzen in Reports auftauchen.
Schritt fĂŒr Schritt: den richtigen Typ fĂŒr jeden Zeitwert wĂ€hlen
Die Wahl zwischen TIMESTAMPTZ und TIMESTAMP beginnt mit einer Frage: Beschreibt dieser Wert einen echten Moment, der passiert ist, oder eine lokale Zeit, die genau so bleiben soll?
1) Trenne echte Ereignisse von geplanten Lokalzeiten
Mache ein schnelles Inventar deiner Spalten.
Echte Ereignisse (Klicks, Zahlungen, Logins, Sendungen, Sensormessungen, Support-Nachrichten) sollten in der Regel als TIMESTAMPTZ gespeichert werden. Du willst einen eindeutigen Instant, auch wenn Leute ihn aus verschiedenen Zeitzonen betrachten.
Geplante Lokalzeiten sind anders: âLaden öffnet um 09:00â, âAbholfenster 16:00â18:00â, âAbrechnung lĂ€uft am 1. um 10:00 lokale Zeitâ. Diese sind oft besser als TIMESTAMP plus separates Zeitzonenfeld aufgehoben, weil die Intention an eine Orts-Uhrzeit gebunden ist.
2) WĂ€hle einen Standard und schreibe ihn auf
FĂŒr die meisten Produkte ist ein guter Default: Ereigniszeiten in UTC speichern, sie in der Zeitzone des Nutzers anzeigen. Dokumentiere das an Stellen, die Leute tatsĂ€chlich lesen: Schema-Notizen, API-Dokumentation und Dashboard-Beschreibungen. Definiere auch, was âGeschĂ€ftstagâ bedeutet (UTC-Tag, GeschĂ€ftszone-Tag oder Viewer-lokaler Tag), denn diese Wahl bestimmt die tĂ€gliche Berichterstattung.
Eine kurze Checkliste, die praktisch funktioniert:
- Markiere jede Zeitspalte als âEvent instantâ oder âlocal scheduleâ.
- Default: Event-Instants als
TIMESTAMPTZin UTC speichern. - Beim Schemawechsel sorgfĂ€ltig backfillen und Stichproben manuell prĂŒfen.
- API-Formate standardisieren (immer
Zoder Offset fĂŒr Instants einschlieĂen). - Session-Zeitzone explizit in ETL-Jobs, BI-Connectors und Hintergrundarbeitern setzen.
Sei vorsichtig bei âconvert and backfillâ-Arbeiten. Das Ăndern eines Spaltentyps kann die Bedeutung stillschweigend Ă€ndern, wenn alte Werte unter einer anderen Session-Zeitzone interpretiert wurden.
HĂ€ufige Fehler, die Off-by-One-Day- und DST-Bugs verursachen
Die meisten Zeitfehler sind nicht âPostgreSQL ist seltsamâ. Sie entstehen, weil man den richtig aussehenden Wert mit der falschen Bedeutung speichert und verschiedene Schichten den fehlenden Kontext raten lassen.
Fehler 1: Eine Wanduhrzeit speichern, als wÀre sie absolut
Eine hĂ€ufige Falle ist, lokale Wanduhrzeiten (z. B. â2026-03-29 09:00â in Berlin) in einem TIMESTAMPTZ zu speichern. PostgreSQL behandelt das als Instant und konvertiert es basierend auf der aktuellen Session-Zeitzone. Wenn die beabsichtigte Bedeutung âimmer 9 Uhr lokalâ war, ist diese verloren. Unter einer anderen Session-Zeitzone verschiebt sich die angezeigte Stunde.
FĂŒr Termine speichere die lokale Zeit als TIMESTAMP plus separate Zeitzone (oder Standort). FĂŒr tatsĂ€chlich stattgefundene Ereignisse (Zahlungen, Logins) speichere den Instant als TIMESTAMPTZ.
Fehler 2: Unterschiedliche Umgebungen, unterschiedliche Annahmen
Dein Laptop, Staging und Produktion teilen vielleicht nicht dieselbe Zeitzone. Eine Umgebung lÀuft in UTC, eine andere in lokaler Zeit, und "group by day"-Reports beginnen auseinanderzugehen. Die Daten Ànderten sich nicht, die Session-Einstellung schon.
Fehler 3: Zeitfunktionen ohne Kenntnis ihrer Eigenschaften verwenden
now() und current_timestamp sind innerhalb einer Transaktion stabil. clock_timestamp() Ă€ndert sich bei jedem Aufruf. Wenn du Timestamps an mehreren Stellen in einer Transaktion erzeugst und diese Funktionen mischst, können Reihenfolge und Dauer merkwĂŒrdig erscheinen.
Fehler 4: Zweimal (oder gar nicht) konvertieren
Ein hÀufiger API-Fehler: Die App konvertiert eine lokale Zeit nach UTC, sendet sie als naiven String, und die Datenbank-Session konvertiert nochmal, weil sie annimmt, die Eingabe sei lokal. Das Gegenteil passiert auch: Die App sendet eine lokale Zeit, markiert sie aber mit Z (UTC), und sie wird bei der Darstellung verschoben.
Fehler 5: Nach Datum gruppieren, ohne die beabsichtigte Zeitzone zu nennen
âTages-Summenâ hĂ€ngt davon ab, welche Tagesgrenze du meinst. Wenn du mit date(created_at) auf einem TIMESTAMPTZ gruppierst, folgt das Ergebnis der Session-Zeitzone. SpĂ€tabendliche Ereignisse können so in den vorherigen oder nĂ€chsten Tag rutschen.
Bevor du ein Dashboard oder eine API auslieferst, ĂŒberprĂŒfe die Basics: WĂ€hle pro Chart eine Reporting-Zeitzone und wende sie konsistent an, schlieĂe Offsets oder Z in API-Payloads ein, halte Staging und Produktion in der Zeit-Policy synchron, und sei explizit, welche Zeitzone du beim Gruppieren meinst.
Schnelle Checks, bevor du ein Dashboard oder eine API auslieferst
Zeitfehler kommen selten von einer einzelnen schlechten Abfrage. Sie entstehen, weil Speicherung, Reporting und API jeweils leicht unterschiedliche Annahmen treffen.
Benutze eine kurze Pre-Ship-Checkliste:
- FĂŒr reale Ereignisse (Anmeldungen, Zahlungen, Sensormeldungen) speichere den Instant als
TIMESTAMPTZ. - FĂŒr geschĂ€fts-lokale Konzepte (Abrechnungsdatum, Reporting-Datum) speichere ein
DATEoderTIME, nicht einen Timestamp, den du spÀter konvertieren willst. - Setze die Session-Zeitzone bewusst in geplanten Jobs und Report-Runnables.
- In API-Antworten: Offset oder
ZeinschlieĂen und bestĂ€tigen, dass der Client das als zeitzonenbewusst interpretiert. - Teste die DST-Ăbergangswoche fĂŒr mindestens eine Zielzeitzone.
Eine schnelle End-to-End-Validierung: Nimm ein bekanntes Edge-Case-Ereignis (z. B. 2026-03-08 01:30 in einer DST-beobachtenden Zone) und verfolge es durch Speicherung, Abfrageausgabe, API-JSON und das finale Chart-Label. Wenn das Chart das richtige Datum, aber das Tooltip die falsche Stunde zeigt (oder umgekehrt), hast du eine Konversionsdifferenz.
Beispiel: warum zwei Teams ĂŒber dieselben Tageszahlen streiten
Ein Support-Team in New York und ein Finance-Team in Berlin schauen auf dasselbe Dashboard. Der Datenbankserver lĂ€uft in UTC. Alle bestehen darauf, dass ihre Zahlen richtig sind, aber âgesternâ ist je nach Blickwinkel verschieden.
Das Ereignis: Ein Kundenticket wird am 10. MĂ€rz um 23:30 in New York erstellt. Das ist 04:30 UTC am 11. MĂ€rz und 05:30 in Berlin. Ein realer Moment, drei verschiedene Kalenderdaten.
Wenn die Erstellung als TIMESTAMP (ohne Zeitzone) gespeichert wurde und deine App annimmt, es sei âlokalâ, kannst du still Geschichte umschreiben. New York könnte 2026-03-10 23:30 als New-York-Zeit deuten, wĂ€hrend Berlin denselben gespeicherten Wert als Berliner Zeit interpretiert. Dieselbe Zeile landet so an verschiedenen Tagen fĂŒr verschiedene Betrachter.
Wenn sie als TIMESTAMPTZ gespeichert ist, speichert PostgreSQL den Instant konsistent und konvertiert nur bei Anzeige oder Formatierung. Deshalb verĂ€ndert die Wahl zwischen TIMESTAMPTZ und TIMESTAMP, was âein Tagâ in Reports bedeutet.
Die Lösung ist, zwei Ideen zu trennen: den Moment, in dem das Ereignis passiert ist, und das Reporting-Datum, das du verwenden willst.
Ein praktisches Muster:
- Speichere die Ereigniszeit als
TIMESTAMPTZ. - Entscheide die Reporting-Regel: Viewer-local (persönliche Dashboards) oder eine GeschÀftszeitzone (firmenweite Finanzen).
- Berechne das Reporting-Datum zur Abfragezeit mit dieser Regel: konvertiere den Instant in die gewÀhlte Zone und nimm dann das Datum.
NĂ€chste Schritte: Zeitverhalten im Stack standardisieren
Wenn das Zeitverhalten nicht dokumentiert ist, wird jeder neue Report zu einem Ratespiel. Ziel: Zeitverhalten langweilig und vorhersehbar machen â in Datenbank, APIs und Dashboards.
Schreibe einen kurzen âTime Contractâ, der drei Fragen beantwortet:
- Event time standard: Speichere Event-Instants als
TIMESTAMPTZ(typischerweise in UTC), auĂer du hast einen starken Grund dagegen. - Business time zone: WĂ€hle eine Zone fĂŒr Reports und nutze sie konsequent, wenn du âTagâ, âWocheâ und âMonatâ definierst.
- API format: Sende Timestamps immer mit Offset (ISO 8601 mit
Zoder+/-HH:MM) und dokumentiere, ob Felder âInstantâ oder âlokale Wanduhrzeitâ bedeuten.
FĂŒge kleine Tests rund um DST-Start und DST-Ende hinzu. Die fangen teure Fehler frĂŒh ab. Zum Beispiel: Validiere, dass eine âTages-Summeâ-Abfrage fĂŒr eine feste GeschĂ€ftszone ĂŒber eine DST-Ănderung stabil bleibt, und dass API-Inputs wie 2026-11-01T01:30:00-04:00 und 2026-11-01T01:30:00-05:00 als zwei unterschiedliche Instants behandelt werden.
Plane Migrationen sorgfĂ€ltig. Das Ăndern von Typen und Annahmen vor Ort kann still die Historie in Charts umschreiben. Ein sichererer Weg ist, eine neue Spalte hinzuzufĂŒgen (z. B. created_at_utc TIMESTAMPTZ), sie mit einer ĂŒberprĂŒften Konversion zu backfillen, Lesezugriffe auf die neue Spalte umzustellen und dann die SchreibvorgĂ€nge anzupassen. Lass alte und neue Reports kurz nebeneinander laufen, damit Verschiebungen in tĂ€glichen Zahlen sichtbar werden.
Wenn du einen Ort brauchst, um diesen âTime Contractâ ĂŒber Datenmodelle, APIs und OberflĂ€chen hinweg durchzusetzen, hilft ein einheitliches Build-Setup. AppMaster (appmaster.io) erzeugt Backend, Web-App und APIs aus einem einzigen Projekt, was es leichter macht, Timestamp-Speicher- und Anzeige-Regeln konsistent zu halten, wĂ€hrend deine App wĂ€chst.
FAQ
Verwende TIMESTAMPTZ fĂŒr alles, was zu einem echten Moment gehört (Anmeldungen, Zahlungen, Logins, Nachrichten, Sensordaten). Es speichert einen eindeutigen Zeitpunkt und lĂ€sst sich zuverlĂ€ssig sortieren, filtern und vergleichen. Verwende einfaches TIMESTAMP nur dann, wenn der Wert als Wanduhrzeit genau so bleiben soll, wie er eingegeben wurde â in der Regel zusammen mit einem separaten Zeitzonen- oder Standortfeld.
TIMESTAMPTZ steht fĂŒr einen echten Zeitpunkt; PostgreSQL normalisiert ihn intern und zeigt ihn dann in der Session-Zeitzone an. TIMESTAMP ist nur ein Datum und eine Uhrzeit ohne angehĂ€ngte Zeitzone, PostgreSQL verschiebt es nicht automatisch. Der zentrale Unterschied ist also die Bedeutung: Instant vs. lokale Wanduhrzeit.
Weil die Session-Zeitzone steuert, wie TIMESTAMPTZ bei der Ausgabe formatiert wird und wie manche Eingaben interpretiert werden. Zwei Tools können dieselbe Zeile abfragen und unterschiedliche Uhrzeiten anzeigen, wenn eine Session auf UTC und die andere auf America/Los_Angeles gesetzt ist. FĂŒr Reports und APIs setze die Session-Zeitzone explizit, damit die Ergebnisse nicht von versteckten Defaults abhĂ€ngen.
Weil âein Tagâ von der Grenze der Zeitzone abhĂ€ngt. Wenn ein Dashboard nach der Viewer-Lokalzeit gruppiert, wĂ€hrend ein anderes nach UTC (oder einer GeschĂ€ftszeitzone) gruppiert, können spĂ€tabendliche Ereignisse auf unterschiedliche Kalenderdaten fallen und so die Tageszahlen Ă€ndern. Behebe das, indem du pro Chart eine Gruppierungsregel wĂ€hlst (UTC oder eine bestimmte GeschĂ€ftszeitzone) und diese konsequent in SQL, BI-Tools und Exporten benutzt.
Die Sommerzeit erzeugt fehlende oder doppelt vorkommende lokale Stunden, was LĂŒcken oder doppelte Buckets in lokalen Gruppierungen verursachen kann. Wenn deine Daten echte Momente reprĂ€sentieren, speichere sie als TIMESTAMPTZ und wĂ€hle eine klare Zeitzone fĂŒr die Buckets in der Darstellung. Teste auĂerdem die Woche der DST-Umstellung fĂŒr deine Zielzeitzonen, um Ăberraschungen frĂŒh zu finden.
Nein, PostgreSQL bewahrt bei TIMESTAMPTZ nicht das ursprĂŒngliche Zeitzonen-Label. Es speichert den Zeitpunkt. Bei einer Abfrage wird dieser Zeitpunkt in der Session-Zeitzone angezeigt, die von der ursprĂŒnglichen Zone des Nutzers abweichen kann. Wenn du âzeige es in der Lokalzeit des Kundenâ brauchst, speichere die Zone separat in einer anderen Spalte.
Gib ISO-8601-Timestamps mit Offset zurĂŒck und sei konsistent. Ein einfacher Standard ist, Ereignisinstanzen immer in UTC mit Z zurĂŒckzugeben, und die Clients sie fĂŒr die Anzeige konvertieren zu lassen. Vermeide ânaiveâ Strings wie 2026-03-10 23:30:00, weil Clients die Zeitzone unterschiedlich erraten könnten.
Am Rand konvertieren: Speichere Ereignisinstanzen als TIMESTAMPTZ, und konvertiere dann in die gewĂŒnschte Zeitzone, wenn du anzeigst oder fĂŒr Reports bucketest. Vermeide wiederholte Konvertierungen innerhalb von Triggern, Hintergrundjobs oder ETL-Schritten, auĂer du hast einen klaren Vertrag dafĂŒr. Die meisten Reporting-Probleme entstehen durch doppelte Konvertierung oder durch das Mischen von naiven und zeitzonenbewussten Werten.
Benutze DATE fĂŒr geschĂ€ftliche Konzepte, die wirklich Datumsangaben sind, wie âAbrechnungsdatumâ, âReporting-Datumâ oder âLieferdatumâ. Verwende TIME (oder TIMESTAMP plus separate Zeitzone) fĂŒr ZeitplĂ€ne wie âöffnet um 09:00 lokale Zeitâ. Packe diese nicht in TIMESTAMPTZ, wenn du eigentlich keine einzelne Instant meinst â DST und ZonenĂ€nderungen können die beabsichtigte Bedeutung verschieben.
Erst klĂ€ren, ob es sich um eine Instant-Spalte (TIMESTAMPTZ) oder eine lokale Wanduhrzeit (TIMESTAMP plus Zone) handelt. FĂŒge statt In-Place-Ănderungen besser eine neue Spalte hinzu. Backfille die neue Spalte mit einer ĂŒberprĂŒften Konversion unter einer bekannten Session-Zeitzone und validiere Stichproben um Mitternacht und an DST-Grenzen. Fahre alte und neue Reports zeitgleich nebenher, damit Verschiebungen in den Zahlen sichtbar werden, bevor die alte Spalte entfernt wird.


