## 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 // 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 ```rust 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`: ```text ' 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.