7 Unix-Timestamp-Bugs, die jeder Entwickler schon ausgeliefert hat

Das sind die Timestamp-Fehler, die Produktionsvorfälle verursachen: stille Einheiten-Diskrepanzen, Zeitzonen-Annahmen, das vergessene ×1000, String-Speicherung, mehrdeutiges Parsen und Sommerzeit-Grenzfehler. Jeder Bug enthält das Symptom, die Ursache und einen praktischen Fix.

Bug 1: Fehlendes × 1000 in JavaScript

new Date(1700000000) erzeugt ein Datum nahe Januar 1970, nicht November 2023. Der Date-Konstruktor von JavaScript erwartet Millisekunden, aber die meisten Server-APIs und Datenbanken liefern Unix-Sekunden. Dieser Bug zeigt sich oft zuerst in Admin-Dashboards, weil das Backend-Payload gültiges JSON ist und die UI einfach das falsche Jahr rendert.

  • Wrong: new Date(response.created_at) — if created_at is Unix seconds
  • Right: new Date(response.created_at * 1000)
  • Detection: if your date shows a year near 1970, the timestamp is in seconds not milliseconds
  • Safe wrapper: const toDate = ts => new Date(ts < 1e11 ? ts * 1000 : ts)

Bug 2: Gemischte Einheiten an einer Systemgrenze

JavaScript liefert Millisekunden. Python, Go und die meisten serverseitigen APIs liefern Sekunden. Wenn JavaScript einen Timestamp ohne Umwandlung an ein Python-Backend sendet, interpretiert das Backend einen Millisekundenwert als Sekunden und platziert das Ereignis im Jahr 55792. Die umgekehrte Richtung ist genauso schlimm: Die UI erhält Sekunden, gibt sie direkt an new Date() und zeigt Januar 1970.

  • JavaScript sends: Date.now() → 1700000000000 (ms)
  • Python receives: datetime.fromtimestamp(1700000000000) → year 55792
  • Fix: divide by 1000 before sending to a non-JavaScript system
  • Better fix: use ISO 8601 strings at API boundaries — they are unambiguous

Bug 3: Sich auf die lokale Zeitzone des Servers verlassen

Code, der Pythons datetime.fromtimestamp() ohne UTC-Angabe nutzt, liefert je nach konfigurierter Server-Zeitzone unterschiedliche Ergebnisse. Es funktioniert in der Entwicklung und bricht in Produktion, wenn in einer anderen Region deployt wird. Dieselbe Bug-Kategorie tritt in Node auf, wenn Code Daten ohne explizite timeZone-Option formatiert und das Ergebnis dann in Tests einfriert.

  • Wrong: datetime.fromtimestamp(ts) — uses server's local timezone
  • Right: datetime.fromtimestamp(ts, tz=datetime.timezone.utc)
  • Wrong in JS: date.toLocaleDateString() — uses the Node process timezone
  • Right in JS: date.toISOString() or Intl.DateTimeFormat with an explicit timeZone option

Bug 4: Timestamps als Strings speichern

Einen Timestamp als formatierten String in einer VARCHAR-Spalte zu speichern wirkt harmlos, bis man nach Zeit sortieren, einen Bereich abfragen oder rechnen muss. String-Vergleich von Daten funktioniert nur mit strikten, nullgefüllten ISO-8601-Feldern. Lesbare Strings wie Nov 15, 2023 oder 1/2/24 sind Anzeigeformate, keine Speicherformate.

  • Wrong: INSERT INTO events (created) VALUES ('Nov 15, 2023') — not sortable
  • Wrong: INSERT INTO events (created) VALUES ('2023-11-15') — loses time component
  • Right: use a native DATETIME/TIMESTAMPTZ column or BIGINT for Unix milliseconds
  • If a string is unavoidable: use ISO 8601 with full precision: '2023-11-15T06:13:20Z'

Bug 5: Mehrdeutige Datums-Strings parsen

new Date('2024-01-01') und new Date('2024/01/01') sehen gleich aus, verhalten sich aber unterschiedlich. Das ISO-8601-Bindestrichformat wird als UTC-Mitternacht geparst; das Schrägstrichformat ist implementierungsabhängig und die meisten Browser parsen es als lokale Mitternacht. Ein Datumswähler, ein API-Payload und eine Datenbankzeile können dasselbe Kalenderdatum zeigen und doch verschiedene Momente darstellen.

  • new Date('2024-01-01') → January 1, 2024 00:00:00 UTC (correct, explicit)
  • new Date('2024/01/01') → January 1, 2024 00:00:00 local time (varies by runtime)
  • new Date('January 1, 2024') → local time, may be rejected by strict parsers
  • Safe rule: always use ISO 8601 with explicit timezone: new Date('2024-01-01T00:00:00Z')

Bug 6: 24 Stunden addieren für morgen

86.400.000 Millisekunden zu addieren wirkt wie ein sauberer Weg zu morgen, aber lokale Kalendertage sind nicht immer 24 Stunden lang. Bei Sommerzeit-Umstellungen kann ein lokaler Tag 23 oder 25 Stunden haben. Wenn die Produktlogik den nächsten lokalen Kalendertag meint, nutze Kalenderarithmetik in der Zielzeitzone, nicht Dauerarithmetik in UTC-Millisekunden.

  • Falsch für Kalendertage: next = new Date(date.getTime() + 86400000)
  • Besser in lokalem Date-Code: kopiere das Date, dann rufe setDate(d.getDate() + 1) auf
  • Für Server-Code: nutze eine zeitzonenbewusste Bibliothek oder Datenbank-Datumsarithmetik
  • Für wiederkehrende Pläne: speichere local_date, local_time und timezone_id und berechne jedes Vorkommen
  • Füge Tests für die Start- und Enddaten der Sommerzeit in der Zielzeitzone hinzu

Bug 7: Inklusive Tagesende-Filter

Eine häufige Analytics-Abfrage nutzt created_at >= start und created_at <= endOfDay. Das wirkt vernünftig, erzeugt aber Präzisions-Bugs, wenn die Datenbank Millisekunden, Mikrosekunden oder Nanosekunden speichert. Das sicherere Muster ist ein halboffener Bereich: größer oder gleich dem Start und strikt kleiner als der Start der nächsten Periode.

  • Risky: WHERE created_at <= '2026-05-19 23:59:59'
  • Safer: WHERE created_at >= '2026-05-19' AND created_at < '2026-05-20'
  • Half-open ranges work for seconds, milliseconds, microseconds, and nanoseconds
  • The same pattern works for months: created_at >= monthStart AND created_at < nextMonthStart

Checkliste zur Vermeidung in Produktion

Die meisten Timestamp-Vorfälle sind durch Benennung, Tests und explizite Grenzen vermeidbar. Das Ziel ist nicht, jede Zeile Datums-Code clever zu machen; es ist, Einheit, Zeitzone und Bereichssemantik langweilig offensichtlich zu machen.

  • Benenne numerische Felder mit ihrer Einheit: createdAtMs, expiresAtSeconds, imported_at_ms
  • Nutze UTC zum Speichern und explizite IANA-Zeitzonen zur Anzeige
  • Bevorzuge ISO-8601-Strings mit Z oder Offsets an von Menschen geprüften API-Grenzen
  • Nutze halboffene Bereiche für Datumsfilter
  • Teste rund um den 1. Januar, Schalttage, Sommerzeit-Umstellungen und die Jahr-2038-Grenze

FAQ zu Unix-Timestamp-Bugs

Was ist der häufigste Unix-Timestamp-Bug?
Sekunden zu übergeben, wo Millisekunden erwartet werden, oder umgekehrt. In JavaScript landet new Date(unixSeconds) in 1970, weil der Konstruktor Millisekunden erwartet; multipliziere den 10-stelligen Wert zuerst mit 1000.
Wie verhindere ich Sekunden-vs-Millisekunden-Bugs?
Benenne Felder mit ihrer Einheit (createdAtMs, expiresAtSeconds), wandle an Systemgrenzen um und bevorzuge ISO-8601-Strings in API-Verträgen, damit der Wert selbsterklärend ist.
Warum bricht das Addieren von 86.400.000 ms „morgen“?
Lokale Kalendertage dauern bei Sommerzeit-Umstellungen 23 oder 25 Stunden, also kann das Addieren fester 24 Stunden auf das falsche Datum fallen. Nutze Kalenderarithmetik in der Zielzeitzone.