ReviewOS

zig-utils/zig-js

Private ABI: JSGlobalObject default-timezone override (setTimeZone)

#303
Closed chris opened this 9 days ago ·
9 days ago

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)), then vm.dateCache.resetIfNecessarySlow() on success; returns the override's acceptance boolean (ZigGlobalObject.cpp:3117)

Acceptance

  • Export implemented in src/c_api.zig with the pinned semantics: process-wide default-timezone override consumed when no explicit zone is given; false for unknown zones with state unchanged; empty input clears the override (WTF's reset); true on acceptance
  • Real consumers wired (no symbol-only state, #259): Intl.DateTimeFormat default timeZone (including Date#toLocaleString, which routes through it) and Temporal.Now default 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 test validated on clean-HEAD worktrees (baseline vs candidate, same pinned base 7be5f42d): 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=intl pass, all Temporal/Intl-named tests green in the full run
  • README/docs counts + evidence updated; benchmark matrix unchanged

Evidence

  • Commits: f2bc3d9f feat(abi): override the process default time zone (#303); d1abe65a docs(abi): publish default-timezone override evidence (#303) — both pushed to main
  • 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 so resolvedOptions().timeZone and Temporal.Now.timeZoneId() echo canonical IDs. Offset-form zones are rejected like zig-js's named-zone path.
  • Documented boundary: zig-js Date local-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; widening Date local methods remains an engine feature, not an ABI boundary.

Sign in to comment on this issue.