Skip to content

Time-Zone & Calendar Virtualization: Intl.*, Temporal (polyfill), DST/Offset Drift Simulation #3

@hoangsonww

Description

@hoangsonww

Summary
Extend time warping beyond Date to time-zone-aware behavior: virtualize Intl.DateTimeFormat, Intl.RelativeTimeFormat, and (optionally) the Temporal polyfill so tests/simulations can deterministically exercise DST transitions, custom UTC offsets, and clock drift—without mutating the host environment (no global TZ side effects).


Why

  • Many bugs only appear around DST boundaries/offset changes.
  • Apps format with Intl.* or use Temporal; warping Date alone isn’t enough.
  • CI hosts differ in TZ; reproducible tests need a virtual tz layer.

Scope

  • Virtual TZ layer: specify IANA zone (e.g., "America/New_York") or a custom fixed offset (e.g., UTC+05:45), independent of host TZ.
  • DST simulation: step over ambiguous/missing local times; expose flags (isAmbiguous, isGap).
  • Clock drift/skew: add linear drift (ppm) or step skew (+/- ms) on top of virtual wall clock.
  • Intl.* patching: intercept new Intl.DateTimeFormat(...).format() (and formatToParts), Intl.RelativeTimeFormat, honoring the virtual tz/locale.
  • Temporal (polyfill) hook: optional adapter so Temporal.Now.*() and ZonedDateTime use the virtual clock/tz.
  • No global process.env.TZ writes; sandboxed patches only.

API (draft)

import { installTimeZone, updateTimeZone, uninstallTimeZone } from "time-warp-manipulation/tz";

installTimeZone({
  zone: "America/Los_Angeles",         // or { fixedOffsetMinutes: -420 }
  driftPpm: 0,                          // e.g., +50 ppm to simulate fast clocks
  skewMs: 0,                            // instantaneous skew applied to wall clock
  patch: { intl: true, temporal: true } // temporal hooks optional
});

// Change zone/drift at runtime
updateTimeZone({ zone: "Europe/Berlin", driftPpm: 25 });

// Tear down
uninstallTimeZone();

Acceptance Criteria

  • new Date(utcMs) + Intl.DateTimeFormat(tz).format() equals output produced by virtual layer, regardless of host TZ.
  • Deterministic behavior across DST gap (spring forward) and fold (fall back); surface isGap/isAmbiguous.
  • Works in Node, Bun, and browser/JSDOM; graceful no-op where Intl lacks zone data.
  • Plays nicely with existing time warp (no double offsets); documented order of installation.

Tests

  • Golden tests for multiple IANA zones across 5+ years (including leap years).
  • Property tests around DST transitions (gap/fold windows).
  • Drift/skew round-trip: after advancing virtual 1h with +100 ppm drift, expected delta ≈ 3600.36s.
  • Temporal polyfill integration tests (Temporal.Now.zonedDateTimeISO(zone)).

Implementation Notes

  • Use a compact TZ data bundle (e.g., subset of IANA via @formatjs/intl-timezone or generated tables) to avoid heavy deps; tree-shake by zone.
  • Wrap Intl.DateTimeFormat.prototype.format & formatToParts; map input instants → virtual local time using our tz table.
  • Provide withVirtualTimeZone(fn) helper for scoped application in tests.

Metadata

Metadata

Assignees

Labels

documentationImprovements or additions to documentationenhancementNew feature or requestgood first issueGood for newcomershelp wantedExtra attention is neededquestionFurther information is requested

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions