Warum liegen Ihre Log-Zeiten immer 8 Stunden daneben?

Zeitstempel haben keine eigene Zeitzone. Die 8-Stunden-Differenz entsteht fast immer beim Umwandeln in eine lesbare Zeit.

Zuerst das Ergebnis: Ein Unix-Zeitstempel trägt keine Zeitzone. Er ist nur die Anzahl der Sekunden seit 1970-01-01 00:00:00 UTC. Die beobachteten „8 Stunden Versatz" entstehen fast immer in dem Schritt, in dem die Zahl zu einem lesbaren Text wird.

Was ein Zeitstempel wirklich ist

Ein Unix-Zeitstempel ist eine ganze Zahl, die einen Zeitpunkt darstellt. Er kennt weder „Berliner Zeit" noch „New Yorker Zeit" – derselbe Zeitpunkt ergibt überall dieselbe Zahl. Genau deshalb ist das Speichern von Zeitstempeln die sicherste Variante: Ein Serverumzug oder eine geänderte Systemzeitzone verändert sie nicht.

Zu beachten ist allein die Genauigkeit: 10 Stellen bedeuten Sekunden, 13 Stellen Millisekunden. Wird ein Millisekundenwert als Sekunden gelesen, landet man im Jahr 50000; umgekehrt fällt man auf Januar 1970 zurück. Diesen Fehler gibt es in jeder Programmiersprache.

Drei Ursachen für die 8 Stunden

1. Speichern und Anzeigen folgen unterschiedlichen Konventionen. Das Backend speichert UTC, das Frontend formatiert lokal – beides ist richtig, nur sagt niemand, welche Zone gemeint war.

2. Der Server läuft nicht auf UTC. Manche Images nutzen standardmäßig Asia/Shanghai, andere UTC. Derselbe Code schreibt auf zwei Maschinen Logzeilen mit 8 Stunden Abstand. Wenn Logzeiten nicht zusammenpassen, prüfen Sie zuerst date und timedatectl.

3. Strings bekommen beim Parsen eine implizite Zeitzone. Ein Wert wie 2026-10-19 00:00:00 ohne Offset wird von Browsern und Node als lokale Zeit gelesen, von manchen Bibliotheken als UTC. Ein String, zwei Lesarten, 8 Stunden Unterschied.

Schnelle Selbstprüfung

Im Zweifel zwei Dinge tun: Erstens denselben Zeitstempel als UTC und als lokale Zeit lesen – unterscheiden sich die Ergebnisse um ganze Stunden, ist es ein Zeitzonenproblem. Zweitens die erwartete Zeit in einen Zeitstempel umrechnen und mit dem Wert im Log vergleichen. Eine Differenz von 28.800 Sekunden sind genau 8 Stunden.

Drei Gewohnheiten, die die meisten Fehler vermeiden

  • Immer UTC-Zeitstempel speichern oder ISO 8601 mit Offset (z. B. 2026-10-19T02:00:00Z)
  • Beim Anzeigen die Zeitzone ausdrücklich angeben, nie den Standard der Laufzeitumgebung übernehmen
  • In Schnittstellen immer einen Offset mitgeben oder klar sagen, dass der Wert UTC ist

In einem Satz

UTC speichern, in der Zeitzone des Nutzers anzeigen, mit explizitem Offset parsen. Diese drei Regeln verhindern die meisten „die Zeit stimmt nicht"-Meldungen.

Ein Zeitpunkt, fünf Schreibweisen

Schreiben Sie denselben Moment — 2026-10-19 02:00:00 UTC — auf fünf verschiedene Arten, und die Ursache der Verwirrung liegt offen:

  • 1792375200 — Unix-Sekunden. Absolut, eindeutig.
  • 1792375200000 — Unix-Millisekunden. Absolut, eindeutig.
  • 2026-10-19T02:00:00Z — ISO 8601, das abschließende Z bedeutet UTC. Absolut.
  • 2026-10-19T10:00:00+08:00 — ISO 8601 mit ausdrücklichem Offset. Absolut.
  • 2026-10-19 10:00:00 — ohne jede Zonenangabe. Kein Zeitpunkt: Der Wert bedeutet die lokale Zone des Programms, das ihn liest.

Die ersten vier zeigen auf denselben Punkt der Zeitachse. Die fünfte zeigt auf jeder Maschine auf einen anderen Punkt. Fast jeder Streit darüber, dass „die Zeiten nicht passen", entsteht daraus, dass die fünfte Form wie eine der ersten vier behandelt wird.

Die Voreinstellungen unterscheiden sich je nach Technik

Hier entstehen die Fehler. Dieselbe Absicht — „eine Zeit speichern" — wird in jeder Schicht anders umgesetzt:

  • MySQL: TIMESTAMP rechnet den Wert beim Schreiben über die Sitzungszeitzone nach UTC um und beim Lesen zurück. DATETIME speichert genau das, was übergeben wurde. Falscher Spaltentyp, und ein Client in einer anderen Zone liest einen anderen Wert.
  • PostgreSQL: timestamptz speichert UTC und behält die Zonensemantik, timestamp speichert keine Zone. Die Dokumentation empfiehlt standardmäßig die erste Variante.
  • Java: Instant ist ein absoluter Punkt, LocalDateTime trägt keine Zone. Wird ein LocalDateTime direkt in einen String serialisiert, ist die Zoneninformation verloren.
  • Python: datetime gibt es naiv (ohne Zone) und aware (mit Zone); die Subtraktion der beiden Varianten wirft eine Ausnahme. Eine Zone per zoneinfo anzuhängen ist heute Standard.
  • JavaScript: Ein Date ist intern immer ein Millisekundenstempel, aber getHours() und toString() geben in der Zone der Laufzeitumgebung aus, während toISOString() immer UTC liefert.

Eine Regel deckt alle Fälle ab: Jeder Typ, der „lokale Zeit" heißt, trägt keine Zoneninformation und verfälscht sich, sobald er eine Maschinengrenze überschreitet.

Keine Zonenkürzel, sondern IANA-Namen

CST allein kann China Standard Time (UTC+8), US Central Standard Time (UTC−6) oder Cuba Standard Time (UTC−5) bedeuten. EST ist ebenso unsicher: Es ignoriert die Sommerzeit, während die US-Ostküste im Sommer tatsächlich auf EDT (UTC−4) läuft.

Verwenden Sie IANA-Bezeichner: Asia/Shanghai, America/New_York, Europe/Berlin. Sie enthalten die vollständige Sommerzeit-Historie, werden in der tz-Datenbank des Systems gepflegt und bleiben über beliebige Jahre korrekt.

Ein leicht vergessenes Detail: China hatte von 1986 bis 1991 eine Sommerzeit, Sommermomente jener Jahre liegen also bei UTC+9. Asia/Shanghai rechnet das richtig, ein fest eingetragenes UTC+8 liegt eine Stunde daneben.

Drei Fragen, bevor Sie Code lesen

  • Ist der Wert ein Zeitpunkt oder eine Uhrzeitangabe? Bei einem Zahlenstempel liegt der Fehler zwangsläufig in der Formatierung. Bei einem String klären Sie zuerst, in welcher Zone er geschrieben wurde.
  • Sind Erzeuger, Speicher und Browser sich über die Zone einig? Wenn nicht, existiert irgendwo eine Umrechnung — und genau die ist verdächtig.
  • Ist die Differenz eine ganze Stundenzahl? Acht Stunden oder 5,5 Stunden (Indien, UTC+5:30) sind ein Zonenproblem. Abweichungen von Sekunden deuten eher auf Uhrzeitsynchronisation oder Präzision hin.

Diese drei Fragen schließen die Hälfte der Möglichkeiten aus, bevor Sie überhaupt ein Logfile öffnen.

Passende Werkzeuge