Vom Leiden der Internet-Uhrzeitangaben nach RFC 3339
Womit man als Informatiker so seine Arbeits-, Frei- und Lebenszeit verheizt.
Hat mich heute wieder einige Zeit gekostet:
Mir fiel auf, dass ein in Go geschriebenes Programm über deren Parser für Zeitangaben die Ausgabe von date nach RFC 3339 nicht nach RFC 3339 akzeptieren will.
Worum geht’s?
Es gibt in der IT- und Unix-Welt historisch gewachsen verschiedene Formate, um Datum und Uhrzeit darzustellen, die sich auch in der Lesbarkeit für Menschen unterscheiden. Sehr bekannt sind dabei die Formate nach RFC 3339 und ISO 8601.
Ich führe es Euch mal vor:
% date So 14. Dez 03:16:54 CET 2025 % date --rfc-3339=seconds 2025-12-14 03:17:17+01:00 % date --iso-8601=seconds 2025-12-14T03:17:27+01:00
wie man sieht, sind sich die Formate RFC 3339 und ISO 8601 sehr ähnlich. Sie unterscheiden sich – auf den ersten Blick – darin, dass bei 3339 ein Leerzeichen zwischen Datum und Uhrzeit ist, während ISO 8601 ein T dazwischen macht. (Vertraute wissen, dass statt des + auch ein Z stehen kann).
Das hat Vor- und Nachteile. Die Version mit dem Leerzeichen ist für Menschen leichter lesbar, wird aber von Shells usw. als Trennzeichen für Parameter fehlinterpretiert. Einen Befehl mit 2025-12-14 03:17:17+01:00 als Parameter aufzurufen geht schief, wenn eine Shell das macht und keine Anführungszeichen darumherum sind. Typischer, gern gemachter Programmierfehler. Das kann bei der schwerer lesbaren Version mit dem T nicht passieren.
Aber, ach.
Versucht man nun aber, das in Go zu parsen (=wieder einzulesen und in eine Uhrzeit umzuwandeln), und verwendet man dafür kein selbstdefiniertes Format, sondern etwas wie zeit,err = time.Parse(time.RFC3339,s), wie es eigentlich vorgesehen ist, dann geht das nicht, denn die Laufzeitbibliothek von Go definert das als RFC3339 = "2006-01-02T15:04:05Z07:00", will also das T.
Bug-Report bei Go aufgemacht. Antwort:
Your date tool is wrong.
The T is required as per RFC 3339: https://datatracker.ietf.org/doc/html/rfc3339#section-5.6
Also habe ich einen Bug report bei coreutils (der neu geschriebenen Version der tools in Rust, bei der das auch so ist) aufgemacht, dass sie sich nicht an RFC 3339 halten. Antwort:
https://datatracker.ietf.org/doc/html/rfc3339#section-5.6
defines
date-time = full-date “T” full-timeThat is the definition of ISO 8601 given in RFC 3339. Here is the preceding paragraph:
The following profile of ISO 8601 [ISO8601] dates SHOULD be used in new protocols on the Internet. This is specified using the syntax description notation defined in [ABNF].
Here is the subsequent paragraph detailing that RFC 3339 allows a space instead of a “T”:
NOTE: ISO 8601 defines date and time separated by “T”. Applications using this syntax may choose, for the sake of readability, to specify a full-date and full-time separated by (say) a space character.
Heißt: RFC 3339 bezieht sich zwar auf ISO 8601 und empfiehlt das („should“), erlaubt aber zum Wohle der Lesbarkeit auch ein Leerzeichen. Schwammige, unklare Definition.
Und dann prallen die verschiedenen Auslegungen unerbittlich aufeinander, jeder von beiden hat natürlich unbedingt Recht und weiß es besser als der andere. und man sitzt dann da und muss erst einmal debuggen, warum etwas nicht funktioniert, und in den Quelltexten sowohl der Go-Laufzeitumgebung, als auch der coreutils nach den Stellen suchen, und sich Workarounds ausdenken – weil man ja auch sonst nichts zu tun hat.
Und dann wundert man sich, wenn irgendwo aus wundersamen Gründen irgendwas nicht geht – oder schlimmer noch, scheinbar geht. Denn wenn irgendwer bei der Benutzung dieser Go-Bibliothek vergisst, den Fehlerzustand zu überprüfen, weil er meint, das hat doch immer funktioniert, warum soll das jetzt nicht mehr funktionieren, liefert die Funktion als Ergebnisdatum 0001-01-01 00:00:00 +0000 UTC, dann kommt man ziemlich genau bei Jesus wieder raus.
Alles in allem mit Wundern, Testen, Ausprobieren, Testprogramm, Download, Lesen, Suchen, Bug Reports wieder mal locker zwei, drei Stunden vergeudet.