Einleitung
Ein Unix-Timestamp ist eines der grundlegendsten Konzepte in der Informatik. Er repräsentiert einen bestimmten Moment in der Zeit als einfache ganze Zahl — die Anzahl der Sekunden, die seit dem Unix-Epoch (1. Januar 1970, 00:00:00 UTC) vergangen sind. Dieses einfache, universelle Format bildet die Grundlage für alles: von Datenbankeinträgen und API-Antworten bis hin zu Protokolldateien und geplanten Aufgaben.
Im Gegensatz zu für Menschen lesbaren Datumszeichenketten wie "9. April 2024" hat ein Unix-Timestamp keine Zeitzone, keine Lokalisierung und keine Mehrdeutigkeit. Die Zahl 1712620800 bezieht sich auf der ganzen Welt auf exakt denselben Moment. Diese Eigenschaft macht ihn zur gemeinsamen Sprache für Datum und Uhrzeit in der Softwareentwicklung.
Geschichte des Unix-Epoch
Das Unix-Betriebssystem wurde Ende der 1960er und Anfang der 1970er Jahre von Ken Thompson, Dennis Ritchie und Kollegen in den Bell Labs entwickelt. Die Zeitverfolgung wurde von Anfang an in den Kernel integriert, aber die genaue Wahl des Epoch-Datums entwickelte sich während der frühen Entwicklung.
Einige der frühesten Unix-Versionen verwendeten den 1. Januar 1971 als Epoch. Andere experimentierten mit dem 1. Januar 1969. Schließlich wurde der 1. Januar 1970, 00:00:00 UTC standardisiert — ein "rundes" Datum, das nah genug an der Entstehung des Systems lag, damit Timestamps für echte Ereignisse kleine positive Ganzzahlen wären.
Die Wahl des 1. Januar 1970 ist im Wesentlichen willkürlich. Was wichtig ist, ist nicht das Datum selbst, sondern die Konsistenz der Konvention. Da sich alle Systeme auf denselben Epoch einigen, können Timestamps zwischen Programmen, Sprachen und Plattformen ohne Konvertierungsaufwand ausgetauscht werden.
Diese Konvention wurde später in POSIX (der Portable Operating System Interface) formalisiert, die einen Unix-Timestamp als die Anzahl der Nicht-Schaltsekunden seit 1970-01-01T00:00:00Z definiert.
Sekunden vs. Millisekunden
Nicht alle "Timestamps" sind gleich. Der wichtigste Unterschied liegt in der Einheit:
- Unix-Timestamp (POSIX): Sekunden seit Epoch — z.B.:
1712620800 - JavaScript
Date: Millisekunden seit Epoch — z.B.:1712620800000 - Java
System.currentTimeMillis(): Millisekunden seit Epoch - Go
time.Now().Unix(): Sekunden;time.Now().UnixNano()gibt Nanosekunden - Python
time.time(): Sekunden als Gleitkommazahl
Der Faktor-1000-Unterschied zwischen Sekunden und Millisekunden ist eine häufige Fehlerquelle. Wenn ein Millisekunden-Timestamp an Code übergeben wird, der Sekunden erwartet, ergibt sich ein Datum in der fernen Zukunft (Jahr ~56.000); umgekehrt ergibt sich ein Datum im Januar 1970.
Die Konvertierung ist unkompliziert:
const unix_ms = unix_s * 1000;
const unix_s = Math.floor(unix_ms / 1000);
Eine praktische Faustregel: Wenn Ihr Timestamp eine 10-stellige Zahl ist, ist er wahrscheinlich in Sekunden. Bei 13 Stellen wahrscheinlich in Millisekunden.
ISO 8601 Format und Varianten
ISO 8601 ist der internationale Standard zur Darstellung von Datum und Uhrzeit. Er definiert eine Familie von eindeutigen Zeichenkettenformaten:
2024-04-09 # Nur Datum
2024-04-09T12:00:00 # Lokales Datum/Uhrzeit (keine Zeitzoneninfo)
2024-04-09T12:00:00Z # UTC (Z = Zulu-Zeit = UTC+0)
2024-04-09T20:00:00+08:00 # Mit UTC-Offset (z.B.: Asia/Shanghai)
2024-04-09T12:00:00.123Z # Mit Millisekunden
2024-04-09T12:00:00.123456789Z # Mit Nanosekunden
Das T trennt den Datums- und den Zeitteil. Das Suffix Z (von "Zulu", dem NATO-Buchstabierbetrieb für UTC) bedeutet, dass die Zeit in UTC ist. Ein Offset wie +08:00 bedeutet, dass die Ortszeit 8 Stunden vor UTC liegt.
ISO 8601 ist das empfohlene Format für REST-APIs, Protokolldateien und jedes System, das Zeitdaten über Grenzen hinweg austauscht. Es ist für Menschen lesbar, als Zeichenkette lexikografisch sortierbar und eindeutig.
Zeitzonen und UTC
UTC (Koordinierte Weltzeit) ist der primäre Zeitstandard der Welt. Es ist keine Zeitzone an sich, sondern die Basislinie, von der aus alle Zeitzonen definiert werden. UTC+0 entspricht der Greenwich Mean Time (GMT) im Winter.
Zeitzonen werden als Offsets von UTC ausgedrückt: UTC+5:30 (Indien), UTC-8 (US Pacific Standard Time), UTC+9 (Japan). Rohe Offsets allein sind jedoch nicht ausreichend, um eine Zeitzone vollständig zu beschreiben, da sich Offsets mit der Sommerzeit (DST) ändern.
Die IANA-Zeitzonendatenbank (auch tz-Datenbank oder zoneinfo genannt) ist die maßgebliche Liste aller Zeitzonen der Welt. Sie verwendet Bezeichner wie America/New_York, Europe/Berlin, Asia/Tokyo und Europe/Vienna. Diese Bezeichner umfassen nicht nur den aktuellen UTC-Offset, sondern den vollständigen historischen Verlauf von DST-Regeln und politischen Änderungen.
Alle wichtigen Programmiersprachen und Betriebssysteme enthalten die IANA-Datenbank:
- JavaScript (Node.js):
Intl.DateTimeFormatmit IANA-Bezeichnern - Python:
zoneinfo-Modul (Python 3.9+) oderpytz - Java:
java.time.ZoneId(z.B.:ZoneId.of("Europe/Berlin")) - Go:
time.LoadLocation("Europe/Berlin")
Verwenden Sie niemals rohe UTC-Offsets wie +01:00 zur Darstellung von Zeitzonen in der Anwendungslogik. Verwenden Sie stattdessen IANA-Bezeichner, da sich Offsets saisonal ändern.
Sommerzeitkomplikationen (DST)
Die Sommerzeit ist die Praxis, die Uhren in den Sommermonaten um eine Stunde vorzustellen, um das Abendlicht zu verlängern. Sie wird in den meisten Teilen Nordamerikas und Europas sowie in Teilen Südamerikas, des Nahen Ostens und Ozeaniens beobachtet. Viele Länder, darunter Japan, China und Indien, beobachten die Sommerzeit überhaupt nicht.
DST führt zu zwei klassischen Anomalien:
Frühjahrsumstellung (Spring forward): Die Uhren springen von 2:00 Uhr direkt auf 3:00 Uhr. Das 60-Minuten-Fenster von 2:00 bis 3:00 Uhr existiert in der Ortszeit nie. Wenn Sie einen Job um 2:30 Uhr planen, läuft er entweder um 3:30 Uhr oder wird je nach Scheduler vollständig übersprungen.
Herbstumstellung (Fall back): Die Uhren gehen von 2:00 Uhr zurück auf 1:00 Uhr. Das 60-Minuten-Fenster von 1:00 bis 2:00 Uhr tritt zweimal auf. Wenn Sie einen Protokolleintrag um "1:45 Uhr Ortszeit" aufzeichnen, ist er mehrdeutig — er könnte vom ersten oder zweiten Auftreten dieser Stunde stammen.
Unix-Timestamps sind vollständig immun gegen DST, da sie immer relativ zu UTC sind. Die Zahl 1712620800 bezieht sich immer auf denselben Moment, unabhängig davon, wo Sie sich befinden oder welche Jahreszeit es ist.
Die goldene Regel: Speichern und übertragen Sie Timestamps immer in UTC. Konvertieren Sie in die Ortszeit nur in der Präsentationsschicht, unmittelbar bevor sie einem menschlichen Benutzer angezeigt werden.
Das Jahr-2038-Problem
Das Jahr-2038-Problem (auch Y2K38 oder Unix-Millennium-Bug genannt) ist eine Softwareschwachstelle, die in ihrer Art dem Y2K-Bug des Jahres 2000 ähnelt.
Die Grundursache: Viele Legacy-Systeme speichern Unix-Timestamps als vorzeichenbehaftete 32-Bit-Ganzzahl. Der Maximalwert einer vorzeichenbehafteten 32-Bit-Ganzzahl beträgt 2.147.483.647. Dies entspricht:
2038-01-19 03:14:07 UTC
Eine Sekunde nach diesem Moment läuft eine vorzeichenbehaftete 32-Bit-Ganzzahl über und springt auf den negativsten Wert: -2.147.483.648, was 1901-12-13 20:45:52 UTC entspricht. Systeme, bei denen ein Überlauf auftritt, glauben plötzlich, das Datum sei im Jahr 1901.
Potenziell betroffene Systeme:
- Legacy eingebettete Systeme und IoT-Geräte, die für 32-Bit-Architekturen kompiliert wurden
- Alte Datenbankschemas, die den
TIMESTAMP-Typ von MySQL verwenden (verwendete 32-Bit-Speicherung in Versionen vor 8.0) - 32-Bit-Linux-Kernel (für 64-Bit-Plattformen im Kernel gelöst)
- Einige ältere Dateisysteme, die Änderungszeiten als 32-Bit-Ganzzahlen aufzeichnen
Die Lösung ist unkompliziert: Migrieren Sie die gesamte Timestamp-Speicherung zu vorzeichenbehafteten 64-Bit-Ganzzahlen. Ein 64-Bit-Timestamp kann Daten bis etwa zum Jahr 292.277.026.596 darstellen — weit jenseits jeder praktischen Sorge. Die meisten modernen 64-Bit-Systeme handhaben dies bereits korrekt.
Arbeiten mit Timestamps in verschiedenen Sprachen
JavaScript
// Aktuelle Zeit
const now = Date.now(); // Millisekunden seit Epoch
const unix = Math.floor(now / 1000); // in Sekunden umrechnen
// Unix-Timestamp parsen
const date = new Date(unix * 1000);
console.log(date.toISOString()); // "2024-04-09T12:00:00.000Z"
console.log(date.toLocaleString("de-DE", { timeZone: "Europe/Berlin" }));
Python
import time
import datetime
# Aktueller Unix-Timestamp (Sekunden)
unix = int(time.time())
# In UTC-Datetime umwandeln
dt = datetime.datetime.fromtimestamp(unix, tz=datetime.timezone.utc)
print(dt.isoformat()) # "2024-04-09T12:00:00+00:00"
# zoneinfo für IANA-Zeitzone verwenden
from zoneinfo import ZoneInfo
dt_local = dt.astimezone(ZoneInfo("Europe/Berlin"))
print(dt_local.isoformat())
Go
package main
import (
"fmt"
"time"
)
func main() {
unix := time.Now().Unix() // int64 Sekunden
t := time.Unix(unix, 0).UTC()
fmt.Println(t.Format(time.RFC3339)) // "2024-04-09T12:00:00Z"
loc, _ := time.LoadLocation("Europe/Berlin")
fmt.Println(t.In(loc).Format(time.RFC3339)) // "2024-04-09T14:00:00+02:00"
}
Java
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
long unix = Instant.now().getEpochSecond(); // Sekunden
Instant instant = Instant.ofEpochSecond(unix);
System.out.println(instant.toString()); // "2024-04-09T12:00:00Z"
ZonedDateTime zdt = instant.atZone(ZoneId.of("Europe/Berlin"));
System.out.println(zdt.toString());
Rust
use std::time::{SystemTime, UNIX_EPOCH};
fn main() {
let unix = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Zeit ist rückwärtsgelaufen")
.as_secs(); // u64 Sekunden
println!("{}", unix); // z.B. 1712620800
}
Tabelle gängiger Timestamp-Formate
| Format | Beispiel | Verwendet in |
|---|---|---|
| Unix (Sekunden) | 1712620800 |
Unix/Linux, POSIX-APIs |
| Unix (Millisekunden) | 1712620800000 |
JavaScript, Java |
| Unix (Mikrosekunden) | 1712620800000000 |
PostgreSQL, einige APIs |
| Unix (Nanosekunden) | 1712620800000000000 |
Go, Rust |
| ISO 8601 UTC | 2024-04-09T12:00:00Z |
REST-APIs, Datenbanken |
| ISO 8601 mit Offset | 2024-04-09T20:00:00+08:00 |
Kalender-Apps |
| RFC 2822 | Tue, 09 Apr 2024 12:00:00 +0000 |
E-Mail-Header |
| RFC 3339 | 2024-04-09T12:00:00Z |
Internetprotokolle |
| HTTP-Datum | Tue, 09 Apr 2024 12:00:00 GMT |
HTTP-Header |
Timestamp-Arithmetik
Da ein Unix-Timestamp nur eine Zahl ist, ist Arithmetik auf Timestamps trivial.
Dauer zwischen zwei Timestamps berechnen:
start = 1712620800
end = 1712707200
dauer_sekunden = end - start # 86400 Sekunden = genau 1 Tag
Ein zukünftiges oder vergangenes Datum finden:
const now = Math.floor(Date.now() / 1000);
const eineWocheSpaeter = now + 7 * 24 * 60 * 60; // +604800 Sekunden
const dreissigTageVorher = now - 30 * 24 * 60 * 60; // -2592000 Sekunden
Häufige Zeitdauern in Sekunden:
| Dauer | Sekunden |
|---|---|
| 1 Minute | 60 |
| 1 Stunde | 3.600 |
| 1 Tag | 86.400 |
| 1 Woche | 604.800 |
| 30 Tage | 2.592.000 |
| 1 Jahr (365 Tage) | 31.536.000 |
Hinweis: Für kalenderorientierte Arithmetik (z.B. "1 Monat hinzufügen") verwenden Sie eine Datumsbibliothek statt roher Sekunden, da Monate unterschiedliche Längen haben und DST einige Tage 23 oder 25 Stunden lang machen kann.
Anwendungsfälle
Anwendungsprotokollierung: Protokolleinträge mit Unix-Timestamps können über verteilte Systeme hinweg, die in verschiedenen Zeitzonen laufen, sortiert, gefiltert und verglichen werden — alles ohne Mehrdeutigkeit.
REST-APIs: Das Zurückgeben von Timestamps als Unix-Ganzzahlen vermeidet die Zeitzoneninterpretation auf der Serverseite. Der Client liest die Ganzzahl und formatiert sie in der lokalen Zeitzone des Benutzers.
Datenbanken: Das Speichern von Timestamps als Ganzzahlen (oder als ISO 8601-Zeichenketten) ist portabler als plattformspezifische Datumstypen. PostgreSQLs TIMESTAMPTZ speichert intern in UTC; MySQLs DATETIME (bevorzugt gegenüber TIMESTAMP) vermeidet das Y2038-Limit.
Geplante Aufgaben und Cron-Jobs: Das Berechnen von "täglich um 3:00 Uhr ausführen" in UTC vermeidet DST-Überraschungen. Viele Planungs-Frameworks (Kubernetes CronJobs, GitHub Actions-Zeitpläne) verwenden UTC per Konvention.
Cache-Ablauf und TTL: HTTP Cache-Control: max-age=3600 und Expires-Header verwenden absolute Unix-Timestamps oder relative Sekunden; CDNs und Browser verlassen sich auf präzise Timestamp-Arithmetik, um Caches zu invalidieren.
Event-Sourcing und Auditprotokolle: Unveränderliche Ereignisprotokolle erfordern Timestamps, die Ereignisse eindeutig ordnen. Unix-Timestamps, insbesondere bei Nanosekunden-Auflösung, bieten diese Garantie auch für Hochdurchsatzsysteme.
Best Practices
Timestamps immer in UTC speichern. Speichern Sie niemals die Ortszeit in einer Datenbank. Konvertieren Sie nur in der Präsentationsschicht in die Ortszeit.
64-Bit-Ganzzahlen verwenden. Vermeiden Sie
int32für Timestamps in neuem Code. Selbst wenn Ihr System derzeit nur Daten in der nahen Zukunft verarbeitet, ist 64-Bit der sichere Standard.ISO 8601 für menschenlesbare Serialisierung verwenden. Wenn Sie eine Zeichenkettendarstellung in Protokollen oder APIs benötigen, ist ISO 8601 eindeutig und lexikografisch sortierbar.
IANA-Zeitzonenbezeichner, keine Offsets verwenden.
"Europe/Berlin"ist korrekt;"+02:00"ist fragil, weil sich der Offset zweimal im Jahr ändert.Timestamp-Einheiten validieren. Bevor Sie einen externen Timestamp verwenden, überprüfen Sie, ob er in Sekunden, Millisekunden oder einer anderen Einheit vorliegt. Eine schnelle Überprüfung: Eine 10-stellige Zahl ist wahrscheinlich in Sekunden; 13 Stellen sind wahrscheinlich in Millisekunden.
Niemals Daten mit regulären Ausdrücken in Produktionscode parsen. Verwenden Sie die Standardbibliothek Ihrer Sprache oder eine gut getestete Drittbibliothek.
Vorsicht bei "Mitternacht". In Zeitzonen, die DST beobachten, existiert Mitternacht an bestimmten Daten möglicherweise nicht (Frühjahrsumstellungsübergänge). Verwenden Sie Mittag (12:00 UTC) als sichere "repräsentative" Zeit für reine Datumsberechnungen.
In der Nähe von DST-Übergängen testen. Wenn Ihre Anwendung Planungs- oder Zeitberechnungen umfasst, schreiben Sie Tests, die speziell die Frühjahrs-Vorstell- und Herbst-Rückstellgrenzen für relevante Zeitzonen ausüben.
Häufig gestellte Fragen (FAQ)
F: Was repräsentiert der Unix-Timestamp 0?
A: Den 1. Januar 1970, 00:00:00 UTC — den Unix-Epoch. Negative Timestamps repräsentieren Daten vor 1970.
F: Kann ich Timestamps zum Sortieren verwenden?
A: Ja. Da ein Unix-Timestamp eine monoton wachsende Ganzzahl ist, entspricht das Sortieren nach Timestamp dem chronologischen Sortieren.
F: Ist die Unix-Zeit von Schaltsekunden betroffen?
A: POSIX definiert die Unix-Zeit so, als ob jeder Tag genau 86.400 Sekunden hätte, was bedeutet, dass Schaltsekunden nicht gezählt werden. Ein POSIX-Timestamp ist technisch gesehen "Unix-Zeit" oder "POSIX-Zeit", nicht die "echte" Internationale Atomzeit (TAI). In der Praxis spielt dies für Anwendungscode selten eine Rolle.
F: Was ist das maximale Datum, das mit einem Unix-Timestamp darstellbar ist?
A: Mit einer vorzeichenbehafteten 64-Bit-Ganzzahl entspricht das Maximum dem Jahr 292.277.026.596. Mit einer vorzeichenbehafteten 32-Bit-Ganzzahl ist es der 2038-01-19 03:14:07 UTC.
F: Wie erhalte ich den aktuellen Unix-Timestamp in meinem Browser?
A: Math.floor(Date.now() / 1000) in der Browser-Konsole gibt den aktuellen Unix-Timestamp in Sekunden zurück.
F: Warum zeigt mein Timestamp 1970-01-01, wenn ich ihn konvertiere?
A: Sie übergeben höchstwahrscheinlich Millisekunden an eine Funktion, die Sekunden erwartet (oder umgekehrt). Dividieren Sie durch 1000, wenn Sie ein Datum in der fernen Zukunft sehen; multiplizieren Sie mit 1000, wenn Sie den 1. Januar 1970 sehen.