Parent: #140 Tracked by: #134, #163, #164
Scope
Implemented the one pending timezone export declared in the pinned Home source (packages/runtime/src/jsc/JSGlobalObject.zig @ 7ed99c02) and pinned Bun bindings (ZigGlobalObject.cpp @ 4982b91e), present in both private-ABI inventories:
JSGlobalObject__setTimeZone—WTF::setTimeZoneOverride(Zig::toString(*timeZone)), thenvm.dateCache.resetIfNecessarySlow()on success; returns the override's acceptance boolean (ZigGlobalObject.cpp:3117)
Acceptance
- Export implemented in
src/c_api.zigwith the pinned semantics: process-wide default-timezone override consumed when no explicit zone is given;falsefor unknown zones with state unchanged; empty input clears the override (WTF's reset);trueon acceptance - Real consumers wired (no symbol-only state, #259):
Intl.DateTimeFormatdefaulttimeZone(includingDate#toLocaleString, which routes through it) andTemporal.Nowdefault zone /timeZoneId() - Validation matches the engine's Intl pipeline: ASCII word-case normalization per segment, alias resolution, canonical IANA table check; canonical name stored (so
resolvedOptions().timeZone/timeZoneId()echo canonical IDs); offset-form zones rejected like zig-js's named-zone path - Compiled-fixture coverage (288/288): UTC baseline, null global/string tolerance, unknown-zone rejection without state disturbance, canonical acceptance, explicit-option precedence, process-wide visibility from a foreign VM (WTF parity), lowercase normalization, alias canonicalization (
America/Atka→America/Adak), empty-string reset - Both inventories refreshed: Home 286/431 private implemented (145 pending), Bun 278/421 (143 pending)
zig build test-home-private-abi(288/288 symbols linked; runtime matrix passed),bun-private-abi-audit,c-api-audit(117/117, 294 private profile exports),test-c-api,test-home-public-abi(50/50),zig build test -Dtest-filter=c_api(148/148) green- Full
zig build testvalidated on clean-HEAD worktrees (baseline vs candidate, same pinned base7be5f42d): 1134/1135 both runs, the single failure being the pre-existing gc slab assertion from the in-flight wasm/gc track — zero new failures;-Dtest-filter=temporal/-Dtest-filter=intlpass, all Temporal/Intl-named tests green in the full run - README/docs counts + evidence updated; benchmark matrix unchanged
Evidence
- Commits:
f2bc3d9ffeat(abi): override the process default time zone (#303);d1abe65adocs(abi): publish default-timezone override evidence (#303) — both pushed tomain - Fixture:
Home private value shims: 288/288 symbols linked; runtime matrix passed - Home audit:
implemented-private=286, pending-private=145, unclassified=0 - Bun audit:
implemented-private=278, pending-private=143, unclassified=0 - C-API audit:
117 declarations, 117 complete, 0 pending, 294 private profile exports
Design notes (as implemented)
- The override is a process-wide global mirroring WTF exactly; the fixture proves foreign context groups observe the same zone.
- zig-js keeps no date cache, so the pinned
dateCache.resetIfNecessarySlow()is vacuous and documented as such. - Validation (
interp.validCanonicalTimeZoneName) shares the Intl pipeline's semantics: ASCII word-case normalization per segment, alias resolution, canonical IANA table; the canonical name is stored soresolvedOptions().timeZoneandTemporal.Now.timeZoneId()echo canonical IDs. Offset-form zones are rejected like zig-js's named-zone path. - Documented boundary: zig-js
Datelocal-time methods are UTC-coincident by engine design (interpreter.zig "v1 ignores local timezone"), so the override flows to the Intl/Temporal default-zone consumers that actually consult a default zone; wideningDatelocal methods remains an engine feature, not an ABI boundary.