hoangsonww / hoangsonww/Time-Warp-Manipulation-Library

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

Open
#3 0 comments 0 reactions 1 assignee Claimed by @hoangsonww View on GitHub
documentation enhancement good first issue help wanted question
Dominant language
TypeScript
Stars
11
Forks
7
PR merge metrics
No merged PRs in 30d

Description

**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)

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

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.