## 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

```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.
