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>
181 lines
7.4 KiB
Markdown
181 lines
7.4 KiB
Markdown
## 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.
|