Files
Chili Palmer 1c8dcbdf18 OpenSpec: phase-3-ortszeit archiviert, Delta-Specs gesynct
konsolen-basisbibliothek um drei Anforderungen erweitert: Zeitfunktionen
liefern Ortszeit, Zonenermittlung mit Rueckfallebene, Programmversatz
wirkt auf die Ortszeit.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-04 07:02:09 +02:00

7.4 KiB

Context

Siehe proposal.md — Why. Der Ist-Zustand ist eng umrissen:

  • tb-runtime::datetime rechnet vollständig selbst: Kalenderumrechnung (Howard Hinnant), serielle Datumswerte ab dem 30.12.1899, WEEKDAY, Textformen. Diese Rechnung ist getestet und bleibt.
  • Der einzige Punkt, an dem die Zeitzone eine Rolle spielt, ist jetzt_sekunden() — Sekunden seit der Unix-Epoche. Alles Weitere (jetzt_serial, DATE$, TIME$, TIMER, NOW) baut darauf auf.
  • tb-runtime hat bislang eine einzige Abhängigkeit mit fachlichem Gewicht: unicode-width.

Damit ist die Aufgabe klein: eine Zahl — der UTC-Versatz zu einem Zeitpunkt — kommt künftig von außen.

Goals / Non-Goals

Goals:

  • Zeitfunktionen liefern das, was die Uhr des Rechners zeigt.
  • Sommerzeit wird zum jeweiligen Zeitpunkt berücksichtigt.
  • Die Berührungsfläche zur Bibliothek bleibt eine Funktion, damit sie austauschbar ist und die getestete Kalenderrechnung unberührt bleibt.
  • Zeitverhalten bleibt automatisiert prüfbar, ohne von der Zone des Testrechners abzuhängen.

Non-Goals:

  • Zeitzonenbehaftete Datentypen im Dialekt — das Vorbild kennt nur Wanduhrzeit.
  • Eine Sprachanbindung an die Bibliothek (Zonennamen, Umrechnung zwischen Zonen). Das ist der Stufe-2-Eintrag im PLAN, nicht dieser Change.
  • Historische Zonendaten jenseits dessen, was die Systemdatenbank hergibt.

Decisions

D1: jiff als Zeitzonenbibliothek

Gewählt: jiff — sie liest die Zeitzonendatenbank des Systems und liefert den Versatz zu einem Zeitpunkt ohne Einschränkung.

Alternativen:

Bibliothek Bewertung
jiff Für genau diese Frage gebaut; Systemzonendatenbank; keine Sicherheitsauflage. Gewählt.
chrono (≥ 0.4.20) Gleichwertig sicher, seit 0.4.20 ohne localtime_r (Zonenermittlung über iana-time-zone, Datenbank über einen tz-rs-Zweig). Etablierter, bringt aber Serde-/Ökosystem-Anbindung mit, die hier niemand braucht. Tragfähige zweite Wahl.
time Der lokale Versatz ist auf Unix nur nach ausdrücklichem Opt-in in möglicherweise undefiniertes Verhalten verfügbar (set_soundness). Verworfen — das ist kein Preis für eine Uhrzeit.
Eigenbau (iana-time-zone + TZif-Parser) Hieße, die Zonendatenbank selbst zu lesen und dauerhaft nachzupflegen. Genau das, wofür man eine Bibliothek nimmt. Verworfen.

Warum die Wahl leicht revidierbar bleibt: Die Bibliothek wird an genau einer Stelle aufgerufen (D2). Ein Wechsel zu chrono wäre ein Austausch dieser einen Funktion.

D2: Berührungsfläche ist eine Funktion

tb-runtime::datetime

    utc_versatz(zeitpunkt: i64) -> Option<i32>     // Sekunden, None = Zone unbekannt
        └── einziger Aufruf der Bibliothek

    jetzt_sekunden()  ─┐
    jetzt_serial()     ├── rechnen weiter selbst
    civil_from_days()  │
    weekday() …       ─┘

Die Kalenderrechnung sieht die Bibliothek nie. Sie bekommt nach wie vor Sekunden seit der Epoche — nur eben um den Versatz verschobene.

Warum nicht die Bibliothek durchreichen: Ihre Datums-/Zeittypen wären ein zweites Kalendermodell neben dem des Dialekts (der bei 1899 zählt, WEEKDAY = 1 für Sonntag, CURRENCY-nahe Serienwerte). Zwei Modelle nebeneinander wären eine dauerhafte Fehlerquelle; die vorhandene Rechnung ist getestet und bleibt maßgeblich.

D3: Der Versatz gilt je Zeitpunkt, nicht je Programmlauf

utc_versatz bekommt den Zeitpunkt als Argument. Ein Programm, das über eine Zeitumstellung hinweg läuft, folgt ihr; ein Programm, das mit DATE$ = in einen anderen Teil des Jahres springt, bekommt den dort gültigen Versatz.

Preis: Eine Zonenabfrage je Zeitabfrage. Bei den Aufrufmengen eines Terminalprogramms belanglos; die Bibliothek hält die Zonendaten selbst vor.

D4: Zonenquelle ist umschaltbar — damit Tests nicht von der Maschine abhängen

pub enum Zeitzone {
    /// Zone des Rechners (Vorgabe).
    System,
    /// Fester Versatz in Sekunden — für Tests und den Korpus.
    Fest(i32),
    /// Zone nicht ermittelbar; es gilt UTC.
    Unbekannt,
}

RtState hält eine Zeitzone. Die Vorgabe ist System; schlägt die Ermittlung fehl, wird daraus Unbekannt. Tests und Korpusprogramme setzen Fest(n).

Warum nicht TZ in den Tests setzen: Umgebungsvariablen sind prozessweit, Tests laufen nebenläufig, und set_var ist seit Rust 2024 unsafe. Ein Zustand im RtState ist der offensichtliche Weg — er ist genau so weit sichtbar wie nötig.

Korpus: Das Harness bekommt eine Kopfzeilen-Direktive analog zu ' tb-screen: und ' tb-tempdir:

' tb-tz: +02:00

Damit bleibt die Sollausgabe eines Zeitprogramms unabhängig davon, wo der Testrechner steht.

D5: Rückfallebene ist sichtbar, nicht still

Ohne ermittelbare Zone gilt UTC — ein Abbruch wäre unverhältnismäßig, ein stiller Wechsel aber ein Verstoß gegen den Guiding Principle. Die Laufzeit führt den Zustand mit, und der Zustand ist abfragbar; die Sprachreferenz beschreibt ihn.

Wie ein Programm es erfährt: Über die vorhandene Systemabfrage ENVIRON$ wäre es geraten. Stattdessen bekommt die Laufzeit einen benannten Zustand, den der Runner beim Start auf die Fehlerausgabe schreibt, wenn er Unbekannt ist — einmal, nicht je Abfrage. Ein Programm, das es programmatisch braucht, bekommt es in Stufe 2 über die Bibliotheksanbindung.

D6: Reihenfolge der Umsetzung

  1. Abhaengigkeit + utc_versatz()          -> isoliert testbar
  2. jetzt_sekunden/jetzt_serial umstellen  -> DATE$/TIME$/TIMER/NOW folgen
  3. Zeitzone im RtState + Korpusdirektive  -> Tests werden maschinenunabhaengig
  4. Doku: Abweichung zurueckziehen, PLAN Stufe 2

Risks / Trade-offs

  • Erste schwere Abhängigkeit der Laufzeit → bewusst entschieden (2026-09-04). Die Berührungsfläche ist eine Funktion (D2); ein Wechsel der Bibliothek bleibt ein lokaler Eingriff.
  • Zeitabhängige Tests werden flatterig → deshalb D4: kein Test und kein Korpusprogramm fragt die echte Zone ab. Was die Systemzone betrifft, wird über Fest(n) und Unbekannt geprüft.
  • Zeitumstellung erzeugt mehrdeutige Wanduhrzeiten (Rückstellung) und nicht existierende (Vorstellung) → betrifft nur die Richtung Wanduhr → Zeitpunkt. Die Zeitfunktionen dieses Dialekts gehen die andere Richtung (Zeitpunkt → Wanduhr) und sind davon nicht betroffen. DATEVALUE/TIMEVALUE lesen Wanduhrzeit und rechnen gar nicht um. DATE$ =/TIME$ = setzen einen Versatz gegen die aktuelle Wanduhrzeit — auch das ist eindeutig.
  • Die Systemzonendatenbank kann fehlen (schlanke Container) → D5.
  • Bauzeit und Binärgröße wachsen → für ein Werkzeug, dessen Programme Uhrzeiten anzeigen, ist eine falsche Uhrzeit der größere Preis.

Migration Plan

Rein verhaltensändernd, ohne Formatbruch: .tbc-Dateien, Korpus-Golden- Files und Schnittstellen bleiben unberührt. Das einzige beobachtbare Verhalten, das sich ändert, ist der Wert von DATE$, TIME$, TIMER und NOW — und zwar zum Richtigen hin.

Rücknahme: Ein Zurücksetzen auf UTC wäre Zeitzone::Unbekannt als Vorgabe; die Abhängigkeit bliebe ungenutzt.

Open Questions

  • Ob die Bibliotheksanbindung in Stufe 2 (Zonennamen, Umrechnung zwischen Zonen als BASIC-Funktionen) auf derselben Bibliothek aufsetzt oder eine eigene Wahl trifft, entscheidet Stufe 2. Für diesen Change ohne Wirkung — hier wird nur der Versatz gebraucht.