Intl.DateTimeFormat timeZone option or manual offset math for zone-correct display?
0 reputation · 27 Jan 2023, 05:44 UTC
0 reputation · 27 Jan 2023, 05:44 UTC
A scheduling dashboard stores every timestamp in UTC but must render each one in a per-user IANA zone such as America/New_York or Asia/Tokyo, without mutating the stored instant.
Intl.DateTimeFormat (ECMA-402) takes a timeZone option: it formats an existing Date in a named zone and leaves the underlying epoch untouched. The alternative is manual offset arithmetic — reading an offset via Date.prototype.getTimezoneOffset or a hard-coded value, shifting the Date by that many minutes, then formatting the shifted copy, whose internal timestamp now differs from the stored one.
The open concern is daylight-saving behavior. A fixed manual shift can produce wall-clock times that land in a spring-forward gap or repeat during fall-back, and it pushes zone-rule lookup onto the application. The Intl path delegates those rules to the runtime's ICU data, but formatting output can vary with the engine's ICU version, and legacy environments such as IE11 lack timeZone support entirely.
Assume modern evergreen browsers and Node.js with full ICU data, where ECMA-402 timeZone support is complete; IE11 is out of scope.
For a store-in-UTC, render-per-zone design, which approach holds up more reliably across DST boundaries? And is depending on runtime ICU data an acceptable consistency risk across browsers?
34775 reputation · 27 Jan 2023, 14:30 UTC
For a store-in-UTC, render-per-zone design on modern evergreen browsers and Node with full ICU, use Intl.DateTimeFormat with the timeZone option. Manual offset arithmetic is not reliable across DST boundaries and mutates the stored instant.
Intl delegates DST rules, spring-forward gaps and fall-back overlaps to the runtime's ICU data. A fixed manual shift cannot model zone rule changes and will produce wall-clock errors on transitions.
Depending on runtime ICU data is an acceptable consistency risk for wall-clock correctness in modern evergreen browsers and Node with full ICU, with the caveat that formatting strings and historical rule updates can vary by engine version. For production consistency, pin Node ICU version and test critical transition dates.
new Intl.DateTimeFormat(userLocale, { timeZone: userZone, hour: 'numeric', minute: 'numeric' })Verification: format a UTC instant at a known DST transition, e.g. 2026-03-08T07:00:00Z with timeZone 'America/New_York', and confirm the wall time reflects the post-transition offset without mutating the Date.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.