Zum Hauptinhalt springen

RFC 3339 - Date and Time on the Internet: Timestamps

  • Status: Proposed Standard
  • Veröffentlicht: July 2002
  • Stream: IETF
  • Errata: Keine Errata

Status of this Memo (Status dieses Memos)​

Dieses Dokument spezifiziert ein Internet-Standards-Track-Protokoll für die Internet-Community und fordert Diskussionen und Verbesserungsvorschläge an. Für den Standardisierungsstatus dieses Protokolls siehe die aktuelle Version von "Internet Official Protocol Standards" (STD 1). Die Verbreitung dieses Memos ist nicht beschränkt.


Copyright (C) The Internet Society (2002). All Rights Reserved.


Abstract (Zusammenfassung)​

Dieses Dokument definiert ein Datums- und Zeitformat zur Verwendung in Internetprotokollen, das ein Profil (Profile) des ISO 8601-Standards zur Darstellung von Datum und Uhrzeit unter Verwendung des gregorianischen Kalenders (Gregorian Calendar) ist.


目录 (Inhaltsverzeichnis)​

附录 (Anhänge)​


相关资源 (Verwandte Ressourcen)​


快速参考 (Schnellreferenz)​

Standardformat​

YYYY-MM-DDTHH:MM:SS.sssZ
YYYY-MM-DDTHH:MM:SS.sss±HH:MM

Beispiele​

1985-04-12T23:20:50.52Z
1996-12-19T16:39:57-08:00
1990-12-31T23:59:60Z (Schaltsekunde)
1937-01-01T12:00:27.87+00:20

Wichtiger Hinweis: Dies ist das Standardformat zur Darstellung von Zeitstempeln in Internetprotokollen und wird weitgehend in Protokollen und Datenformaten wie HTTP, JSON, XML usw. verwendet.


1. Einführung​

Datums- und Zeitformate verursachen im Internet viel Verwirrung und Interoperabilitätsprobleme. Dieses Dokument behandelt viele der aufgetretenen Probleme und gibt Empfehlungen zur Verbesserung der Konsistenz und Interoperabilität bei der Darstellung und Verwendung von Datum und Uhrzeit in Internetprotokollen.

Dieses Dokument enthält ein Internet-Profil des ISO 8601 [ISO8601] Standards zur Darstellung von Daten und Zeiten unter Verwendung des gregorianischen Kalenders (Gregorian Calendar).

Es gibt viele Möglichkeiten, wie Datums- und Zeitwerte in Internetprotokollen erscheinen können: Dieses Dokument konzentriert sich auf nur eine gängige Verwendung, nämlich Zeitstempel (Timestamps) für Internetprotokollereignisse. Diese begrenzte Betrachtung hat folgende Konsequenzen:

Einschränkungen und Annahmen für Zeitstempel​

o Aktuelle Ära​

Es wird angenommen, dass sich alle Daten und Zeiten in der „aktuellen Ära" befinden, irgendwo zwischen 0000 n. Chr. und 9999 n. Chr.

o Beziehung zu UTC​

Alle ausgedrückten Zeiten haben eine angegebene Beziehung (Offset) zur koordinierten Weltzeit (Coordinated Universal Time, UTC). (Dies unterscheidet sich von einigen Verwendungen in Planungsanwendungen, bei denen eine lokale Zeit und ein Ort bekannt sein können, die tatsächliche Beziehung zu UTC jedoch von den unbekannten oder nicht erkennbaren Handlungen von Politikern oder Administratoren abhängen kann. Die UTC-Zeit, die 17:00 Uhr am 23. März 2005 in New York entspricht, kann von administrativen Entscheidungen über die Sommerzeit abhängen. Diese Spezifikation vermeidet solche Überlegungen bewusst.)

o Historische Zeitstempel​

Zeitstempel können Zeiten darstellen, die vor der Einführung von UTC aufgetreten sind. Solche Zeitstempel beziehen sich auf die Weltzeit (Universal Time) und verwenden die zum angegebenen Zeitpunkt verfügbare beste Praxis.

o Darstellung von Zeitpunkten​

Datums- und Zeitausdrücke stellen einen Moment in der Zeit (Instant in Time) dar. Beschreibungen von Zeiträumen (Time Periods) oder Intervallen (Intervals) werden hier nicht behandelt.


Wichtige Punkte:

  • Diese Spezifikation konzentriert sich auf Zeitstempel, nicht auf Zeiträume oder Planung
  • Alle Zeiten müssen eine definierte Beziehung zu UTC haben
  • Unterstützt den Datumsbereich von 0000 n. Chr. bis 9999 n. Chr.
  • Vermeidet Abhängigkeit von politischen Entscheidungen bezüglich lokaler Zeitzonen (wie Sommerzeitanpassungen)

2. Definitionen​

Die Schlüsselwörter „MUST", „MUST NOT", „REQUIRED", „SHALL", „SHALL NOT", „SHOULD", „SHOULD NOT", „RECOMMENDED", „MAY" und „OPTIONAL" in diesem Dokument sind wie in RFC 2119 [RFC2119] beschrieben zu interpretieren.


Begriffsdefinitionen​

UTC (Coordinated Universal Time, Koordinierte Weltzeit)​

Koordinierte Weltzeit, wie sie vom Bureau International des Poids et Mesures (BIPM) gepflegt wird.

second (Sekunde)​

Eine Basiseinheit der Zeitmessung im Internationalen Einheitensystem. Sie ist definiert als die Dauer von 9.192.631.770 Zyklen von Mikrowellenlicht, das durch den Hyperfeinübergang von Cäsium-133-Atomen (cesium-133) in ihrem Grundzustand, ungestört durch externe Felder, absorbiert oder emittiert wird.

minute (Minute)​

Ein Zeitraum von 60 Sekunden. Siehe jedoch auch Abschnitt 5.7 und Anhang D zur Darstellung von Schaltsekunden (Leap Seconds) innerhalb von Minuten.

hour (Stunde)​

Ein Zeitraum von 60 Minuten.

day (Tag)​

Ein Zeitraum von 24 Stunden.

leap year (Schaltjahr)​

Im gregorianischen Kalender ein Jahr mit 366 Tagen. Ein Schaltjahr ist ein Jahr, dessen Zahl durch 4 teilbar ist, aber nicht durch 100, es sei denn, es ist auch durch 400 teilbar.

Schaltjahr-Regeln:

if (Jahr % 400 == 0) → Schaltjahr
else if (Jahr % 100 == 0) → Gemeinjahr
else if (Jahr % 4 == 0) → Schaltjahr
else → Gemeinjahr

Beispiele:

  • 2000: Schaltjahr (durch 400 teilbar)
  • 1900: Gemeinjahr (durch 100, aber nicht durch 400 teilbar)
  • 2004: Schaltjahr (durch 4 teilbar)
  • 2001: Gemeinjahr

ABNF (Augmented Backus-Naur Form, Erweiterte Backus-Naur-Form)​

Ein Format zur Darstellung zulässiger Zeichenfolgen in einem Protokoll oder einer Sprache, wie in [ABNF] definiert.

Email Date/Time Format (E-Mail-Datums-/Zeitformat)​

Das von Internet Mail verwendete Datums-/Zeitformat, wie in RFC 2822 [IMAIL-UPDATE] definiert.

Internet Date/Time Format (Internet-Datums-/Zeitformat)​

Das in Abschnitt 5 dieses Dokuments definierte Datumsformat.

Timestamp (Zeitstempel)​

Dieser Begriff wird in diesem Dokument verwendet, um sich auf eine eindeutige Darstellung (Unambiguous Representation) eines Zeitpunkts zu beziehen.

Z​

Ein Suffix, das, wenn es auf eine Zeit angewendet wird, einen UTC-Offset von 00:00 bezeichnet; oft als „Zulu" ausgesprochen, aus der ICAO-Lautschrifttabelle des Buchstabens „Z".

Beispiel:

2002-07-15T10:30:00Z
Repräsentiert: 15. Juli 2002 um 10:30:00 UTC

Weitere Informationen​

Für weitere Informationen zu Zeitskalen siehe:

  • Anhang E von [NTP]
  • Abschnitt 3 von [ISO8601]
  • Die entsprechenden ITU-Dokumente [ITU-R-TF]

Hinweis: Das Verständnis dieser grundlegenden Begriffe ist entscheidend für die korrekte Implementierung und Verwendung dieser Spezifikation, insbesondere der Definitionen von Schaltjahren und Schaltsekunden.


3. Zweistellige Jahreszahlen​

Die folgenden Anforderungen behandeln die Mehrdeutigkeitsprobleme, die zweistellige Jahreszahlen verursachen:

Anforderungen​

o Vierstellige Jahreszahlen sind obligatorisch​

Internetprotokolle müssen (MUST) vierstellige Jahreszahlen in Daten generieren.

Korrekte Beispiele:

✅ 2002-07-15
✅ 1999-12-31

Falsche Beispiele:

❌ 02-07-15
❌ 99-12-31

o Zweistellige Jahreszahlen sind veraltet​

Die Verwendung zweistelliger Jahreszahlen ist veraltet (Deprecated). Wenn eine zweistellige Jahreszahl empfangen wird, sollte (SHOULD) sie nur akzeptiert werden, wenn eine Fehlinterpretation keinen Protokoll- oder Verarbeitungsfehler verursacht (z. B. wenn sie nur für Protokollierungs- oder Verfolgungszwecke verwendet wird).

o Handhabung dreistelliger Jahreszahlen​

Programme, die zweistellige Jahreszahlen verwenden, können Jahre nach 1999 als dreistellig darstellen. Dies tritt auf, wenn das Programm einfach 1900 vom Jahr subtrahiert, ohne die Anzahl der Ziffern zu überprüfen. Programme, die Daten, die von solch fehlerhafter Software generiert wurden, robust verarbeiten möchten, können (MAY) 1900 zu dreistelligen Jahreszahlen hinzufügen.

Beispiel:

Fehlerhafte Programmausgabe: 102 (stellt das Jahr 2002 dar)
Robuste Analyse: 102 + 1900 = 2002

o Handhabung nicht-numerischer Dekadenziffern​

Programme, die zweistellige Jahreszahlen verwenden, können Jahre nach 1999 als ":0", ":1", ... ":9", ";0", ... darstellen. Dies tritt auf, wenn das Programm einfach 1900 vom Jahr subtrahiert und die Dekadenziffer zum US-ASCII-Zeichen Null hinzufügt. Programme, die Daten, die von solch fehlerhafter Software generiert wurden, robust verarbeiten möchten, sollten (SHOULD) nicht-numerische Dekadenziffern erkennen und entsprechend interpretieren.

Beispiel:

Fehlerhafte Programmausgabe:
- '0' + 10 = ':' (stellt die 2000er Jahre dar, ASCII-Code 58)
- '0' + 11 = ';' (stellt die 2010er Jahre dar, ASCII-Code 59)

Robuste Analyse sollte diese Muster erkennen und korrekt konvertieren

Lehren aus dem Y2K-Problem​

Die Probleme mit zweistelligen Jahreszahlen zeigen deutlich, warum alle in Internetprotokollen verwendeten Daten und Zeiten vollständig qualifiziert (Fully Qualified) sein müssen (MUST).


Implementierungsempfehlungen​

Beim Generieren von Daten​

✅ Immer vierstellige Jahreszahlen verwenden: 2024-12-21
❌ Niemals zwei Ziffern verwenden: 24-12-21

Beim Parsen von Daten​

# Beispiel für robustes Parsing
def parse_year(year_str):
if len(year_str) == 4:
return int(year_str) # Korrekte vier Ziffern
elif len(year_str) == 2:
# Veraltet, nur für Rückwärtskompatibilität
year = int(year_str)
if year < 70:
return 2000 + year
else:
return 1900 + year
elif len(year_str) == 3:
# Fehlerhafte Software handhaben
return 1900 + int(year_str)
else:
raise ValueError("Ungültiges Jahresformat")

Warnung: Obwohl dieser Abschnitt beschreibt, wie zweistellige Jahreszahlen behandelt werden, dient dies nur der Rückwärtskompatibilität. Neue Implementierungen dürfen absolut keine (MUST NOT) zweistelligen Jahreszahlen generieren.


4. Lokale Zeit​

4.1. Koordinierte Weltzeit (UTC)​

Da die Sommerzeitregeln für lokale Zeitzonen so kompliziert sind und sich zu unvorhersehbaren Zeiten aufgrund lokaler Gesetze ändern können, wird echte Interoperabilität am besten durch die Verwendung der Koordinierten Weltzeit (UTC) erreicht. Diese Spezifikation berücksichtigt keine lokalen Zeitzonenregeln.

Warum UTC verwenden?

  • ✅ Global einheitlicher Zeitstandard
  • ✅ Nicht von Sommerzeit betroffen
  • ✅ Nicht von politischen Entscheidungen betroffen
  • ✅ Gewährleistet Interoperabilität

4.2. Lokale Offsets​

Der Offset zwischen lokaler Zeit und UTC ist oft nützliche Information. Zum Beispiel bietet in elektronischer Post (RFC2822, [IMAIL-UPDATE]) der lokale Offset eine nützliche Heuristik zur Bestimmung der Wahrscheinlichkeit einer prompten Antwort. Versuche, lokale Offsets mit alphabetischen Zeichenketten zu kennzeichnen, haben in der Vergangenheit zu schlechter Interoperabilität geführt [IMAIL], [HOST-REQ]. Als Ergebnis hat RFC2822 [IMAIL-UPDATE] numerische Offsets obligatorisch gemacht.

Numerische Offset-Berechnung​

Numerische Offsets werden als „Lokalzeit minus UTC" berechnet. Die äquivalente Zeit in UTC kann daher bestimmt werden, indem der Offset von der lokalen Zeit subtrahiert wird.

Beispiel 1:

Lokale Zeit: 18:50:00-04:00
UTC-Zeit: 18:50:00 - (-04:00) = 18:50:00 + 04:00 = 22:50:00Z

Überprüfung: Eastern Daylight Time (EDT) ist UTC-4

Beispiel 2:

Lokale Zeit: 15:30:00+08:00
UTC-Zeit: 15:30:00 - (+08:00) = 15:30:00 - 08:00 = 07:30:00Z

Überprüfung: China Standard Time (CST) ist UTC+8

Wichtige Hinweise​

Hinweis: Gemäß ISO 8601 repräsentieren numerische Offsets nur Zeitzonen, die sich von UTC um eine ganzzahlige Anzahl von Minuten unterscheiden. Viele historische Zeitzonen unterscheiden sich jedoch von UTC um eine nicht-ganzzahlige Anzahl von Minuten. Um solche historischen Zeitstempel exakt darzustellen, müssen (MUST) Anwendungen sie in eine darstellbare Zeitzone konvertieren.

Beispiele historischer Zeitzonen:

Einige lokale Zeiten im späten 19. Jahrhundert:
- Amsterdam: UTC+00:19:32
- Paris: UTC+00:09:21

Diese können in RFC 3339 nicht präzise dargestellt werden und müssen auf die nächste Minute gerundet werden

4.3. Konvention für unbekannten lokalen Offset​

Wenn die Zeit in UTC bekannt ist, aber der Offset zur lokalen Zeit unbekannt ist, kann dies mit einem Offset von "-00:00" dargestellt werden. Dies unterscheidet sich semantisch von einem Offset von "Z" oder "+00:00", was impliziert, dass UTC der bevorzugte Bezugspunkt für die angegebene Zeit ist. RFC2822 [IMAIL-UPDATE] beschreibt eine ähnliche Konvention für E-Mail.

Unterscheidung der drei Darstellungen​

Z oder +00:00:

2002-07-15T10:30:00Z
2002-07-15T10:30:00+00:00

Bedeutung: Diese Zeit IST UTC-Zeit, UTC ist der bevorzugte Bezugspunkt

-00:00:

2002-07-15T10:30:00-00:00

Bedeutung: Die UTC-Zeit ist 10:30:00, aber der lokale Zeitzonen-Offset ist unbekannt
(möglicherweise von einem System, das seine Zeitzoneneinstellung nicht kennt)

Verwendungsszenarien:

Szenario 1: Serverprotokolle, bekanntermaßen UTC → Z verwenden
Szenario 2: Gerät-generierter Zeitstempel, Gerät ist in UTC, kennt aber lokale Zone nicht → -00:00 verwenden
Szenario 3: Explizit in London (GMT) → +00:00 verwenden

4.4. Nicht qualifizierte lokale Zeit​

Eine Anzahl von Geräten, die derzeit mit dem Internet verbunden sind, laufen mit ihren internen Uhren in lokaler Zeit und sind sich UTC nicht bewusst. Während das Internet eine Tradition hat, bei der Gestaltung von Spezifikationen die Realität zu akzeptieren, sollte dies nicht auf Kosten der Interoperabilität geschehen. Da die Interpretation einer nicht qualifizierten lokalen Zeitzone in etwa 23/24 der Welt fehlschlagen wird,

Obligatorische Anforderungen​

Internetprotokolle müssen (MUST) vollständig qualifizierte Zeitstempel generieren.

Dies bedeutet, dass Internetprotokolle lokale Zeit ohne Zeitzoneninformationen nicht (MUST NOT) verwenden dürfen.

Falsche Beispiele:

❌ 2002-07-15T10:30:00 (keine Zeitzoneninformation)

Korrekte Beispiele:

✅ 2002-07-15T10:30:00Z (UTC)
✅ 2002-07-15T10:30:00+08:00 (explizite Zeitzone)
✅ 2002-07-15T10:30:00-00:00 (UTC, aber Zone unbekannt)

Interoperabilitätsprobleme​

Wenn nicht qualifizierte lokale Zeit verwendet wird:

Sender: 2002-07-15T10:30:00 (New Yorker Lokalzeit, tatsächlich UTC-4)
Empfänger in Tokio: Interpretiert als Tokio-Zeit (UTC+9)
Zeitunterschiedsfehler: 13 Stunden!

Implementierungsempfehlungen​

Systemdesign​

# Empfohlen: Immer Zeit in UTC speichern
def store_timestamp():
utc_time = datetime.now(timezone.utc)
return utc_time.isoformat() # 2024-12-21T10:30:00+00:00

# Beim Anzeigen: In lokale Zeitzone des Benutzers konvertieren
def display_timestamp(utc_time, user_timezone):
local_time = utc_time.astimezone(user_timezone)
return local_time.isoformat()

Datenbankspeicherung​

-- Empfohlen: TIMESTAMP WITH TIME ZONE verwenden
CREATE TABLE events (
id SERIAL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

-- Vermeiden: TIMESTAMP WITHOUT TIME ZONE (verursacht Mehrdeutigkeit)

Schlüsselprinzip: Intern in UTC speichern, beim Anzeigen in lokale Zeitzone konvertieren. Niemals Zeitstempel ohne Zeitzoneninformationen für den Datenaustausch verwenden.


5. Datums- und Zeitformat​

Dieser Abschnitt erörtert wünschenswerte Eigenschaften von Datums- und Zeitformaten und definiert ein Profil von ISO 8601 für die Verwendung im Internet.

5.1. Ordering (Sortierung)​

Wenn Datums- und Zeitkomponenten von der am wenigsten präzisen zur präzisesten geordnet werden, wird eine nützliche Eigenschaft erreicht. Unter der Annahme, dass die Zeitzonen der Daten und Zeiten gleich sind (z.B. alle in UTC), unter Verwendung der gleichen Zeichenkette ausgedrückt werden (z.B. alle "Z" oder alle "+00:00"), und alle Zeiten die gleiche Anzahl von Bruchsekundenstellen haben, können Datums- und Zeitzeichenketten als Zeichenketten sortiert werden (z.B. unter Verwendung der strcmp()-Funktion in C) und erzeugen eine zeitlich geordnete Sequenz. Das Vorhandensein optionaler Interpunktion würde diese Eigenschaft verletzen.

Beispiel:

Korrekte Sortierung (Jahr-Monat-Tag Stunde:Minute:Sekunde):
2002-01-15T10:00:00Z
2002-07-20T15:30:00Z
2002-12-31T23:59:59Z

Falsches Format (Monat/Tag/Jahr) kann nicht korrekt sortiert werden:
01/15/2002 10:00:00
12/31/2002 23:59:59 ← String-Sortierung platziert dies vor Juli
07/20/2002 15:30:00

5.2. Human Readability (Menschliche Lesbarkeit)​

Menschliche Lesbarkeit hat sich als wertvolles Merkmal von Internetprotokollen erwiesen. Menschlich lesbare Protokolle reduzieren die Debugging-Kosten erheblich, da telnet oft als Testclient ausreicht und Netzwerkanalysatoren nicht mit Protokollkenntnissen modifiziert werden müssen. Andererseits führt menschliche Lesbarkeit manchmal zu Interoperabilitätsproblemen.

Problembeispiele:

❌ "10/11/1996" ist für den globalen Austausch völlig ungeeignet
USA: 11. Oktober 1996
Europa: 10. November 1996

❌ Übersetzung von Monatsabkürzungen
Englisch: "Jan", "Feb", "Mar"
Französisch: "Jan", "Fév", "Mar" ← Beeinträchtigt Interoperabilität

Da kein Datums- und Zeitformat nach den Konventionen aller Länder lesbar ist, sollten Internetclients darauf vorbereitet sein (SHOULD), Daten in ein für die Lokalität geeignetes Anzeigeformat zu transformieren. Dies kann die Umwandlung von UTC in Ortszeit einschließen.

5.3. Rarely Used Options (Selten verwendete Optionen)​

Ein Format, das selten verwendete Optionen enthält, verursacht wahrscheinlich Interoperabilitätsprobleme. Dies liegt daran, dass selten verwendete Optionen weniger wahrscheinlich in Alpha- oder Beta-Tests verwendet werden, sodass Fehler beim Parsing weniger wahrscheinlich entdeckt werden. Selten verwendete Optionen sollten wann immer möglich obligatorisch gemacht oder weggelassen werden, um der Interoperabilität willen.

Das unten definierte Format enthält nur eine selten verwendete Option: Sekundenbruchteile (Fractions of a Second). Es wird erwartet, dass dies nur von Anwendungen verwendet wird, die eine strikte Sortierung von Datums-/Zeitstempeln erfordern oder ungewöhnliche Präzisionsanforderungen haben.

5.4. Redundant Information (Redundante Informationen)​

Wenn ein Datums-/Zeitformat redundante Informationen enthält, führt es die Möglichkeit ein, dass die redundanten Informationen nicht korrelieren. Zum Beispiel führt das Einbeziehen des Wochentags in ein Datums-/Zeitformat die Möglichkeit ein, dass der Wochentag falsch ist, aber das Datum korrekt ist, oder umgekehrt. Da es nicht schwierig ist, den Wochentag aus dem Datum zu berechnen (siehe Anhang B), sollte der Wochentag nicht in ein Datums-/Zeitformat aufgenommen werden.

Problembeispiel:

❌ "Monday, 2002-07-16T10:00:00Z"
Problem: 16. Juli 2002 ist tatsächlich ein Dienstag, nicht ein Montag
Wenn Tag und Datum nicht übereinstimmen, welchem sollte vertraut werden?

✅ "2002-07-16T10:00:00Z"
Lösung: Wochentag weglassen, bei Bedarf berechnen

5.5. Simplicity (Einfachheit)​

Der vollständige Satz von Datums- und Zeitformaten, der in ISO 8601 [ISO8601] spezifiziert ist, ist ziemlich komplex in dem Versuch, mehrere Darstellungen und Teildarstellungen bereitzustellen. Anhang A enthält einen Versuch, die vollständige Syntax von ISO 8601 in ABNF zu übersetzen. Internetprotokolle haben etwas andere Anforderungen, und Einfachheit hat sich als wichtiges Merkmal erwiesen. Darüber hinaus benötigen Internetprotokolle normalerweise eine vollständige Datenspezifikation, um echte Interoperabilität zu erreichen. Daher wird die vollständige Syntax von ISO 8601 für die meisten Internetprotokolle als zu komplex angesehen.

Der folgende Abschnitt definiert ein Profil von ISO 8601 für die Verwendung im Internet. Es ist eine konsistente Teilmenge des erweiterten ISO 8601-Formats. Einfachheit wird erreicht, indem die meisten Felder und Interpunktionen obligatorisch gemacht werden.

5.6. Internet Date/Time Format (Internet-Datums-/Zeitformat)​

Das folgende Profil von ISO 8601 [ISO8601]-Daten sollte (SHOULD) in neuen Protokollen im Internet verwendet werden. Dies wird unter Verwendung der in [ABNF] definierten Syntaxbeschreibungsnotation spezifiziert.

ABNF-Syntaxdefinition​

date-fullyear   = 4DIGIT
date-month = 2DIGIT ; 01-12
date-mday = 2DIGIT ; 01-28, 01-29, 01-30, 01-31 based on
; month/year
time-hour = 2DIGIT ; 00-23
time-minute = 2DIGIT ; 00-59
time-second = 2DIGIT ; 00-58, 00-59, 00-60 based on leap second
; rules
time-secfrac = "." 1*DIGIT
time-numoffset = ("+" / "-") time-hour ":" time-minute
time-offset = "Z" / time-numoffset

partial-time = time-hour ":" time-minute ":" time-second
[time-secfrac]
full-date = date-fullyear "-" date-month "-" date-mday
full-time = partial-time time-offset

date-time = full-date "T" full-time

Wichtige Hinweise​

Groß-/Kleinschreibung: Gemäß [ABNF] und ISO8601 können die Zeichen "T" und "Z" in dieser Syntax alternativ auch als Kleinbuchstaben "t" bzw. "z" verwendet werden.

Spezifikationen, die dieses Format in Umgebungen verwenden, in denen Groß-/Kleinschreibung signifikant ist (wie XML), können (MAY) die Datums-/Zeitsyntax weiter einschränken, sodass die in der Datums-/Zeitsyntax verwendeten Buchstaben 'T' und 'Z' immer großgeschrieben sein müssen. Anwendungen, die dieses Format generieren, sollten (SHOULD) Großbuchstaben verwenden.

Trennzeichen: ISO 8601 definiert Datum und Zeit getrennt durch "T". Anwendungen, die diese Syntax verwenden, können (MAY) aus Gründen der Lesbarkeit wählen, ein full-date und full-time getrennt durch (zum Beispiel) ein Leerzeichen anzugeben.

Formatbeispiele​

Standardformat:
2002-07-15T10:30:00Z
2002-07-15T10:30:00.123Z
2002-07-15T10:30:00+08:00
2002-07-15T10:30:00-04:00

Mit Sekundenbruchteilen:
2002-07-15T10:30:00.123456Z
2002-07-15T10:30:00.52Z

Lesbare Varianten (nicht standardmäßig, aber erlaubt):
2002-07-15 10:30:00Z
2002-07-15t10:30:00z

5.7. Restrictions (Einschränkungen)​

Das Grammatikelement date-mday repräsentiert die Tagesnummer innerhalb des aktuellen Monats. Der Maximalwert variiert basierend auf Monat und Jahr:

MonatsnummerMonat/JahrMaximales date-mday
01Januar (January)31
02Februar, normal (February, normal)28
02Februar, Schaltjahr (February, leap year)29
03März (March)31
04April30
05Mai (May)31
06Juni (June)30
07Juli (July)31
08August31
09September30
10Oktober (October)31
11November30
12Dezember (December)31

Schaltsekunden​

Das Grammatikelement time-second kann (MAY) am Ende von Monaten, in denen eine Schaltsekunde auftritt, den Wert "60" haben. Schaltsekunden werden verwendet, um UTC nahe an der Rotationszeit der Erde zu halten. Siehe Anhang D für weitere Informationen über Schaltsekunden.

Schaltsekundenbeispiele:

1990-12-31T23:59:60Z  ✅ Gültig (Schaltsekunde am 31. Dezember 1990)
1990-12-31T23:59:61Z ❌ Ungültig (Maximum ist 60)
1990-06-15T23:59:60Z ❌ Ungültig (Schaltsekunden nur am Monatsende)

5.8. Examples (Beispiele)​

Hier sind einige Beispiele für gültige RFC 3339-Datums-/Zeitstempel:

1985-04-12T23:20:50.52Z
Darstellt: 12. April 1985, 23:20:50.52 UTC

1996-12-19T16:39:57-08:00
Darstellt: 19. Dezember 1996, 16:39:57 Pacific Standard Time (PST)
Äquivalentes UTC: 1996-12-20T00:39:57Z

1990-12-31T23:59:60Z
Darstellt: Schaltsekunde am 31. Dezember 1990

1990-12-31T15:59:60-08:00
Darstellt: Schaltsekunde am 31. Dezember 1990 in PST
Äquivalentes UTC: 1990-12-31T23:59:60Z

1937-01-01T12:00:27.87+00:20
Darstellt: 1. Januar 1937, 12:00:27.87, UTC+00:20
(Historisches Zeitzonenbeispiel)

Ungültige Beispiele​

❌ 1985-04-12  (fehlende Zeit)
❌ 23:20:50.52Z (fehlendes Datum)
❌ 1985-04-12 23:20:50.52Z (sollte 'T' nicht Leerzeichen verwenden, obwohl einige Implementierungen es erlauben)
❌ 1985-04-32T23:20:50.52Z (ungültiges Datum: April hat keinen 32. Tag)
❌ 1985-02-29T23:20:50.52Z (ungültiges Datum: 1985 ist kein Schaltjahr)

Implementierungsempfehlung: Immer das Standardformat generieren (unter Verwendung des 'T'-Trennzeichens und des Großbuchstabens 'Z'), aber liberal parsen (akzeptiere 't', 'z' und möglicherweise Leerzeichen-Trennzeichen).


6. Referenzen​

Normative References (Normative Referenzen)​

[ABNF]
Crocker, D. and P. Overell, "Augmented BNF for Syntax Specifications: ABNF", RFC 2234, November 1997.

[ISO8601]
"Data elements and interchange formats -- Information interchange -- Representation of dates and times", ISO 8601:1988(E), International Organization for Standardization, June 1988.

Hinweis: ISO 8601:1988 wurde durch ISO 8601:2000 aktualisiert, das wiederum durch ISO 8601:2004 aktualisiert wurde. RFC 3339 basiert auf der Version von 1988.

[RFC2119]
Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997.

Informative References (Informative Referenzen)​

[IMAIL]
Crocker, D., "Standard for the Format of Arpa Internet Text Messages", STD 11, RFC 822, August 1982.

[IMAIL-UPDATE]
Resnick, P., "Internet Message Format", RFC 2822, April 2001.

[HOST-REQ]
Braden, R., "Requirements for Internet Hosts -- Application and Support", STD 3, RFC 1123, October 1989.

[NTP]
Mills, D., "Network Time Protocol (Version 3) Specification, Implementation and Analysis", RFC 1305, March 1992.

[ITU-R-TF]
"Standard-frequency and time-signal emissions", ITU-R Recommendation TF.460-4, 1986.

[UNICODE]
The Unicode Consortium, "The Unicode Standard", Version 3.0, Reading, MA, Addison-Wesley, 2000, ISBN 0-201-61633-5.


Verwandte RFC-Dokumente​

Vorgängerdokumente​

  • RFC 822 - E-Mail-Format (Standard for the Format of ARPA Internet Text Messages)
  • RFC 2822 - Internet-Nachrichtenformat (Aktualisiert RFC 822)

Verwandte Standards​

  • RFC 2234 - ABNF-Syntaxspezifikation
  • RFC 2119 - RFC-Schlüsselwortdefinition
  • RFC 1305 - Netzwerkzeitprotokoll (NTP)

Nachfolgende Aktualisierungen​

  • RFC 4287 - Atom-Syndication-Format (verwendet RFC 3339-Zeitstempel)
  • RFC 7493 - I-JSON-Nachrichtenformat (empfiehlt RFC 3339)
  • RFC 8259 - JSON-Datenaustauschformat (empfiehlt RFC 3339 für Datum-Zeit)

Externe Standards​

ISO 8601-Serie​

  • ISO 8601:1988 - Version, auf der dieses RFC basiert
  • ISO 8601:2000 - Erste Überarbeitung
  • ISO 8601:2004 - Zweite Überarbeitung
  • ISO 8601-1:2019 - Neueste Version, Teil 1: Grundregeln
  • ISO 8601-2:2019 - Neueste Version, Teil 2: Erweiterungen

Andere verwandte Standards​

  • IETF BCP 14 - Beste aktuelle Praxis bestehend aus RFC 2119 und RFC 8174
  • W3C Date and Time Formats - Basierend auf ISO 8601 und RFC 3339
  • ECMA-262 - JavaScript-Datum-Zeit-Zeichenkettenformat (basierend auf vereinfachtem ISO 8601)

Praktische Anwendungen​

Das RFC 3339-Format wird weithin verwendet in:

Internetprotokollen:

  • HTTP-Date-Header (obwohl HTTP ein anderes in RFC 7231 definiertes Format verwendet)
  • Atom/RSS-Feed-Zeitstempel
  • JSON-API-Zeitstempel
  • XML-Schema-dateTime-Typ

Programmiersprachen:

  • JavaScript Date.toISOString()
  • Python datetime.isoformat()
  • Java Instant.toString()
  • Go time.RFC3339

Datenbanken:

  • PostgreSQL TIMESTAMPTZ
  • MongoDB ISODate
  • MySQL TIMESTAMP with timezone

Hinweis: Obwohl RFC 3339 auf ISO 8601:1988 basiert, ist es ein Profil (Teilmenge) von ISO 8601, keine vollständige Implementierung. RFC 3339 ist strenger und vereinfacht, um die Interoperabilität in Internetprotokollen sicherzustellen.


7. Sicherheitserwägungen​

Da dieses Dokument nur ein Format zur Darstellung von Datum und Uhrzeit spezifiziert, beschränken sich die hier diskutierten Sicherheitsprobleme auf die Auswirkungen, die unsynchronisierte Uhren auf Sicherheitsfunktionen haben.

Sicherheitsrisiken unsynchronisierter Uhren​

1. Zertifikatsvalidierungsfehler​

Unsynchronisierte Uhren können dazu führen, dass Zertifikate fälschlicherweise als abgelaufen oder noch nicht gültig erscheinen.

Risikobeispiel:

Client-Uhr: 2002-07-14T10:00:00Z (1 Tag voraus)
Zertifikatsgültigkeit:
Not Before: 2002-07-15T00:00:00Z
Not After: 2003-07-15T23:59:59Z

Ergebnis: Client lehnt gültiges Zertifikat ab ❌

Umgekehrter Fall:

Client-Uhr: 2003-07-20T10:00:00Z (2 Jahre zurück)
Zertifikatsgültigkeit:
Not After: 2003-07-15T23:59:59Z (bereits abgelaufen)

Ergebnis: Client akzeptiert abgelaufenes Zertifikat ⚠️ Sicherheitsrisiko!

2. Zeitstempel-Verifikations-Bypass​

Viele Sicherheitsprotokolle verlassen sich auf Zeitstempel, um Replay-Angriffe zu verhindern.

Replay-Angriff Beispiel:

Legitime Anfrage, vom Angreifer abgefangen:
POST /transfer HTTP/1.1
Timestamp: 2002-07-15T10:00:00Z
Amount: $1000
Signature: valid_signature

Wenn die Server-Uhr 1 Stunde zurück ist, kann der Angreifer diese Anfrage wiederholen

3. Unzuverlässige Audit-Logs​

Wenn Log-Zeitstempel ungenau sind, werden Sicherheitsaudit und forensische Analyse unmöglich oder unzuverlässig.

Problemszenario:

Server A Logs: 2002-07-15T10:00:00Z - Einbruch erkannt
Server B Logs: 2002-07-15T09:45:00Z - Abnormale Anmeldung (tatsächlich später als A, aber Uhr ist zurück)

Kann keine genaue Angriffs-Zeitleiste erstellen ❌

Schutzempfehlungen​

Verwenden Sie NTP (Network Time Protocol)​

Alle mit dem Internet verbundenen Systeme sollten (SHOULD) NTP oder ähnliche Zeitsynchronisationsprotokolle verwenden.

NTP-Konfigurationsbeispiel:

# NTP-Server konfigurieren
ntpdate -u time.nist.gov

# ntpd-Daemon aktivieren
systemctl enable ntpd
systemctl start ntpd

# Synchronisationsstatus überprüfen
ntpq -p

Zeitstempel-Toleranz​

Implementieren Sie vernünftige Toleranzfenster bei der Validierung von Zeitstempeln.

Implementierungsbeispiel:

def is_timestamp_valid(timestamp, max_age_seconds=300):
"""Überprüfen, ob Zeitstempel innerhalb akzeptabler Zeitfenster liegt"""
now = datetime.now(timezone.utc)
tolerance = timedelta(seconds=max_age_seconds)

# ±5 Minuten Uhrenabweichung erlauben
if abs(now - timestamp) > tolerance:
return False
return True

Verwenden Sie vertrauenswürdige Zeitquellen​

Empfohlene öffentliche NTP-Server:

time.nist.gov        (US-amerikanisches Nationales Institut für Standards und Technologie)
time.google.com (Google)
time.apple.com (Apple)
time.cloudflare.com (Cloudflare)
pool.ntp.org (NTP Pool Projekt)

Beste Praktiken zur Zertifikatsvalidierung​

# Uhrenabweichung bei der Zertifikatsvalidierung berücksichtigen
def verify_certificate(cert, clock_tolerance=timedelta(minutes=5)):
now = datetime.now(timezone.utc)

# Not Before nachsichtig prüfen
if now < (cert.not_before - clock_tolerance):
raise CertificateNotYetValid()

# Not After streng prüfen (Sicherheit zuerst)
if now > cert.not_after:
raise CertificateExpired()

Zeitzonen-bezogene Sicherheitsprobleme​

1. Zeitzonen-Verwirrungsangriffe​

Inkonsistente Zeitzonenbehandlung kann zu Sicherheitsumgehungen führen.

Schwachstellenbeispiel:

Benutzereinreichung: 2002-07-15T23:00:00-08:00
System A parst als: 2002-07-16T07:00:00Z (korrekt)
System B parst als: 2002-07-15T23:00:00Z (inkorrekt, ignoriert Zeitzone)

Wenn System B für Zugriffskontrollentscheidungen verwendet wird, kann unbefugter Zugriff erlaubt werden

2. Sommerzeit-Grenzen​

Mehrdeutigkeiten oder Sicherheitsprobleme können bei Sommerzeitübergängen auftreten.

Risiko-Momente:

10. März 2002 2:00 → 3:00 (1 Stunde überspringen)
Problem: 2:30 existiert nicht, wie soll dieser Zeitstempel behandelt werden?

3. November 2002 2:00 → 1:00 (1 Stunde wiederholen)
Problem: 1:30 tritt zweimal auf, welches ist korrekt?

RFC 3339 Lösung: UTC-Offset verwenden, um Mehrdeutigkeit zu beseitigen:

✅ 2002-11-03T01:30:00-05:00  (EDT, vor Ende der Sommerzeit)
✅ 2002-11-03T01:30:00-04:00 (EST, nach Ende der Sommerzeit)

Sicherheitsauswirkungen von Schaltsekunden​

Obwohl selten, kann eine unsachgemäße Behandlung von Schaltsekunden Probleme verursachen.

Potenzielle Probleme:

1990-12-31T23:59:60Z  (Schaltsekunde)

Wenn das System Schaltsekunden nicht unterstützt:
- Kann gültige Zeitstempel ablehnen
- Kann Sortierfehler verursachen
- Kann 1-Sekunden-Zeitunterschiede verursachen

Empfehlung:

# Schaltsekunden nachsichtig behandeln
def parse_timestamp(ts_string):
try:
return datetime.fromisoformat(ts_string)
except ValueError as e:
# Prüfen, ob es eine Schaltsekunde ist (Sekunde ist 60)
if ':60Z' in ts_string or ':60+' in ts_string or ':60-' in ts_string:
# 60 Sekunden in 00 Sekunden der nächsten Minute konvertieren
ts_string = ts_string.replace(':60', ':59')
return datetime.fromisoformat(ts_string) + timedelta(seconds=1)
raise

Sicherheits-Checkliste​

Bei der Implementierung von RFC 3339-Zeitstempeln sicherstellen:

  • Systemuhren mit NTP synchronisieren
  • Immer UTC für interne Speicherung und Vergleich verwenden
  • Angemessene Toleranz bei der Validierung von Zeitstempeln implementieren
  • Zeitzonen-Offsets korrekt behandeln
  • Alle zeitbezogenen Sicherheitsereignisse protokollieren
  • Systemuhr-Genauigkeit regelmäßig überprüfen
  • Uhrenabweichung bei Zertifikatsvalidierung berücksichtigen
  • Replay-Angriffs-Schutz implementieren (Nonce + Zeitstempel)
  • Nachsichtig parsen, streng generieren
  • Grenzfälle testen (Schaltsekunden, Schaltjahre, Monatsenden)

Schlüsselprinzip: Verlassen Sie sich nicht auf vom Client bereitgestellte Zeitstempel für kritische Sicherheitsentscheidungen. Verwenden Sie immer serverseitige vertrauenswürdige Zeitquellen.


Appendix A. ISO 8601 Collected ABNF​

Diese Informationen basieren auf der Version von 1988 von ISO 8601. In der Revision von 2000 können einige Änderungen vorhanden sein.

Erklärung​

ISO 8601 spezifiziert keine formale Grammatik für die von ihm definierten Datums- und Zeitformate. Das Folgende ist ein Versuch, eine formale Grammatik aus ISO 8601 zu erstellen. Dies dient nur zu Informationszwecken und kann Fehler enthalten. ISO 8601 bleibt die maßgebliche Referenz.

Mehrdeutigkeiten und Interpretationen​

Beachten Sie, dass aufgrund von Mehrdeutigkeiten in ISO 8601 einige Interpretationen notwendig waren:

  1. Mischen von Basis- und erweiterten Formaten: ISO 8601 ist nicht klar, ob das Mischen von Basis- und erweitertem Format zulässig ist. Diese Grammatik erlaubt das Mischen.

  2. 24 Stunden: ISO 8601 ist nicht klar, ob die Stunde 24 nur zulässig ist, wenn Minuten und Sekunden 0 sind. Diese Grammatik nimmt an, dass Stunde 24 in jedem Kontext zulässig ist.

  3. Datumsbeschränkungen: Die Beschränkungen in Abschnitt 5.7 bezüglich date-mday gelten.

  4. "T"-Trennzeichen: ISO 8601 spezifiziert, dass "T" unter bestimmten Umständen weggelassen werden kann. Diese Grammatik erfordert "T", um Mehrdeutigkeit zu vermeiden.

  5. Dezimalpunkt: ISO 8601 erfordert (in Abschnitt 5.3.1.3), dass, wenn der Dezimalbruch kleiner als 1 ist, ihm eine "0" vorangestellt werden muss. Anhang B.2 von ISO 8601 gibt Beispiele mit Dezimalbrüchen, denen keine "0" vorangestellt ist. Diese Grammatik geht davon aus, dass Abschnitt 5.3.1.3 korrekt ist und Anhang B.2 fehlerhaft ist.

Vollständige ISO 8601 ABNF-Grammatik​

date-century    = 2DIGIT  ; 00-99
date-decade = DIGIT ; 0-9
date-subdecade = DIGIT ; 0-9
date-year = date-decade date-subdecade
date-fullyear = date-century date-year
date-month = 2DIGIT ; 01-12
date-wday = DIGIT ; 1-7 ; 1 is Monday, 7 is Sunday
date-mday = 2DIGIT ; 01-28, 01-29, 01-30, 01-31
date-yday = 3DIGIT ; 001-365, 001-366
date-week = 2DIGIT ; 01-52, 01-53

datepart-fullyear = [date-century] date-year ["-"]
datepart-ptyear = "-" [date-subdecade ["-"]]
datepart-wkyear = datepart-fullyear / datepart-ptyear

dateopt-century = "-" / date-century
dateopt-fullyear = "-" / datepart-fullyear
dateopt-year = "-" / (date-year ["-"])
dateopt-month = "-" / (date-month ["-"])
dateopt-week = "-" / (date-week ["-"])

datespec-full = datepart-fullyear date-month ["-"] date-mday
datespec-year = date-century / dateopt-century date-year
datespec-month = "-" dateopt-year date-month [["-"] date-mday]
datespec-mday = "--" dateopt-month date-mday
datespec-week = datepart-wkyear "W"
(date-week / dateopt-week date-wday)
datespec-wday = "---" date-wday
datespec-yday = dateopt-fullyear date-yday

date = datespec-full
/ datespec-year
/ datespec-month
/ datespec-mday
/ datespec-week
/ datespec-wday
/ datespec-yday

time-hour = 2DIGIT ; 00-24
time-minute = 2DIGIT ; 00-59
time-second = 2DIGIT ; 00-58, 00-59, 00-60
time-fraction = ("," / ".") 1*DIGIT
time-numoffset = ("+" / "-") time-hour [[":"] time-minute]
time-zone = "Z" / time-numoffset

timeopt-hour = "-" / (time-hour [":"])
timeopt-minute = "-" / (time-minute [":"])

timespec-hour = time-hour [[":"] time-minute [[":"] time-second]]
timespec-minute = timeopt-hour time-minute [[":"] time-second]
timespec-second = "-" timeopt-minute time-second
timespec-base = timespec-hour / timespec-minute / timespec-second

time = timespec-base [time-fraction] [time-zone]

iso-date-time = date "T" time

RFC 3339 vs Vollständiges ISO 8601​

RFC 3339 ist eine eingeschränkte Teilmenge von ISO 8601, keine vollständige Implementierung:

MerkmalISO 8601RFC 3339
Basisformat (20020715)✅ Unterstützt❌ Nicht unterstützt
Erweitertes Format (2002-07-15)✅ Unterstützt✅ Unterstützt
Wochendaten (2002-W29-1)✅ Unterstützt❌ Nicht unterstützt
Ordinaldaten (2002-196)✅ Unterstützt❌ Nicht unterstützt
Teildaten (2002-07)✅ Unterstützt❌ Nicht unterstützt
24 Stunden (2002-07-16T24:00:00)✅ Unterstützt❌ Nicht unterstützt
Zeitzone "Z"✅ Unterstützt✅ Unterstützt
Numerischer Zeitzonen-Offset✅ Unterstützt✅ Unterstützt (obligatorisch)
Bruchsekunden✅ Unterstützt✅ Unterstützt

Gründe für die RFC 3339-Vereinfachung​

RFC 3339 wählte eine vereinfachte Teilmenge für:

  1. Interoperabilität: Implementierungsvariationen reduzieren
  2. Klarheit: Mehrdeutigkeit vermeiden
  3. Vollständigkeit: Vollständige Datum-Zeit-Informationen erfordern
  4. Einfachheit: Einfacher zu implementieren und zu testen

Hinweis: Wenn vollständige ISO 8601-Funktionalität (wie Wochendaten) benötigt wird, konsultieren Sie den ISO 8601-Standard direkt. RFC 3339 konzentriert sich auf die häufigsten Zeitstempel-Anwendungsfälle in Internetprotokollen.


Appendix B. Wochentag​

Dieser Anhang zeigt, wie man den Wochentag aus jedem gregorianischen Kalenderdatum berechnet. Dies ist wichtig, um zu verstehen, warum RFC 3339 keine Wochentagsinformationen enthält—weil sie präzise berechnet werden können.

Zellers Kongruenz​

Ein häufig verwendeter Algorithmus zur Berechnung des Wochentags ist Zellers Kongruenz, erfunden von Christian Zeller im Jahr 1882.

Formel​

h = (q + ⌊13(m+1)/5⌋ + K + ⌊K/4⌋ + ⌊J/4⌋ - 2J) mod 7

Wobei:

  • h: Wochentag (0 = Samstag, 1 = Sonntag, 2 = Montag, ..., 6 = Freitag)
  • q: Tag des Monats (1-31)
  • m: Monat (3-14, wobei 3 = März, 4 = April, ..., 12 = Dezember, 13 = Januar, 14 = Februar)
  • K: Jahr des Jahrhunderts (year % 100)
  • J: Jahrhundert (⌊year/100⌋)
  • ⌊x⌋: Abrundungsfunktion

Hinweis: Januar und Februar werden als 13. und 14. Monat des Vorjahres behandelt.

Python-Implementierung​

def day_of_week_zeller(year, month, day):
"""
Wochentag mit Zellers Formel berechnen
Gibt zurück: 0=Samstag, 1=Sonntag, ..., 6=Freitag
"""
# Januar und Februar werden als Monate 13 und 14 des Vorjahres behandelt
if month < 3:
month += 12
year -= 1

q = day
m = month
K = year % 100
J = year // 100

h = (q + (13 * (m + 1)) // 5 + K + K // 4 + J // 4 - 2 * J) % 7

# In gängiges Format konvertieren: 0=Montag, ..., 6=Sonntag
# Zeller: 0=Sa, 1=So, 2=Mo, 3=Di, 4=Mi, 5=Do, 6=Fr
# Anpassen auf: 0=Mo, 1=Di, 2=Mi, 3=Do, 4=Fr, 5=Sa, 6=So
return (h + 5) % 7

def day_name(year, month, day):
"""Namen des Wochentags zurückgeben"""
days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday',
'Friday', 'Saturday', 'Sunday']
return days[day_of_week_zeller(year, month, day)]

# Beispiele
print(day_name(2002, 7, 15)) # Monday
print(day_name(2000, 1, 1)) # Saturday
print(day_name(1999, 12, 31)) # Friday

Einfacherer Algorithmus​

Für Programmierimplementierungen kann ein intuitiverer Algorithmus verwendet werden:

def day_of_week_simple(year, month, day):
"""
Vereinfachte Wochentagsberechnung
Gibt zurück: 0=Montag, ..., 6=Sonntag
"""
# Kumulative Tage vor jedem Monat (kein Schaltjahr)
t = [0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4]

if month < 3:
year -= 1

y = year % 100
c = year // 100

return (y + y // 4 + c // 4 - 2 * c + t[month - 1] + day) % 7

JavaScript-Implementierung​

function dayOfWeek(year, month, day) {
// JavaScript Date-Objekt berechnet automatisch den Wochentag
const date = new Date(year, month - 1, day);
const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday',
'Thursday', 'Friday', 'Saturday'];
return days[date.getDay()];
}

// Beispiele
console.log(dayOfWeek(2002, 7, 15)); // Monday

Überprüfungsbeispiele​

DatumWochentagVerifiziert
2002-07-15Montag (Monday)✅
2000-01-01Samstag (Saturday)✅
1999-12-31Freitag (Friday)✅
1985-04-12Freitag (Friday)✅
1990-12-31Montag (Monday)✅

Warum RFC 3339 keinen Wochentag enthält​

1. Redundante Information​

Der Wochentag kann präzise aus dem Datum berechnet werden, daher führt seine Aufnahme zu potenziellen Inkonsistenzen:

Falsches Beispiel:
"Monday, 2002-07-16T10:00:00Z"

Problem: 2002-07-16 ist tatsächlich Dienstag, nicht Montag
Welchem sollte vertraut werden? Wochentag oder Datum?

2. Erhöhte Komplexität​

Parser müssen Validierung und Inkonsistenzen zwischen Wochentag und Datum behandeln.

3. Lokalisierungsprobleme​

Wochentagsnamen unterscheiden sich zwischen Sprachen:

Englisch: Monday, Tuesday, Wednesday, ...
Französisch: Lundi, Mardi, Mercredi, ...
Deutsch: Montag, Dienstag, Mittwoch, ...

4. Beeinflusst Zeitpunkt nicht​

Der Wochentag beeinflusst die Bestimmung des Zeitpunkts nicht, er dient nur der menschlichen Lesbarkeit.

Empfehlung​

Wenn Sie den Wochentag anzeigen müssen:

from datetime import datetime

# RFC 3339-Zeitstempel parsen
timestamp = "2002-07-15T10:00:00Z"
dt = datetime.fromisoformat(timestamp.replace('Z', '+00:00'))

# Wochentag berechnen und anzeigen
day_name = dt.strftime('%A')
print(f"{timestamp} is a {day_name}")
# Ausgabe: 2002-07-15T10:00:00Z is a Monday

Fazit: Da der Wochentag präzise und deterministisch aus dem Datum berechnet werden kann, ist seine Aufnahme in das Zeitstempelformat nicht nur unnötig, sondern schädlich.


Appendix D. Schaltsekunden​

Dieser Anhang erläutert das Konzept, die Geschichte und die Behandlung von Schaltsekunden in RFC 3339.

Was sind Schaltsekunden?​

Eine Schaltsekunde wird gelegentlich zur Koordinierten Weltzeit (UTC) hinzugefügt, um UTC mit der Erdrotation synchron zu halten.

Warum Schaltsekunden?​

Atomzeit (TAI):

  • Basierend auf Atomuhren, extrem stabil
  • 1 Sekunde = 9.192.631.770 Cäsiumatom-Schwingungen
  • Ändert sich nie

Erdrotation:

  • Nicht perfekt gleichmäßig
  • Beeinflusst durch Gezeitenreibung
  • Wird allmählich langsamer (~1,4ms/Tag pro Jahrhundert)
  • Geschwindigkeit unvorhersehbar

Wie Schaltsekunden funktionieren​

Beispiel positive Schaltsekunde​

Normales Monatsende:
23:59:58
23:59:59
00:00:00 (nächster Tag)

Mit positiver Schaltsekunde:
23:59:58
23:59:59
23:59:60 ← Schaltsekunde!
00:00:00 (nächster Tag)

RFC 3339 Darstellung​

1990-12-31T23:59:60Z  ✅ Gültig (Schaltsekunde am 31. Dez 1990)
2012-06-30T23:59:60Z ✅ Gültig (Schaltsekunde am 30. Jun 2012)
2015-06-30T23:59:60Z ✅ Gültig (Schaltsekunde am 30. Jun 2015)
2016-12-31T23:59:60Z ✅ Gültig (Schaltsekunde am 31. Dez 2016)

Historische Schaltsekunden​

Seit Einführung von UTC 1972:

Datum         UTC-Zeit        TAI-UTC
1972-06-30 23:59:60Z +11s
1972-12-31 23:59:60Z +12s
1990-12-31 23:59:60Z +26s
2012-06-30 23:59:60Z +35s
2015-06-30 23:59:60Z +36s
2016-12-31 23:59:60Z +37s (neueste)

Hinweis:

  • Schaltsekunden nur am 30. Juni oder 31. Dezember hinzugefügt
  • 27 Schaltsekunden seit 1972
  • Neueste war 31. Dezember 2016

Wichtiger Punkt: RFC 3339 erlaubt Schaltsekunden, aber die meisten Implementierungen ordnen sie für praktische Kompatibilität der folgenden Sekunde zu.