fix(frontend): anchor session times to the campaign timezone (#95) #185
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/95-campaign-timezone"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Fixes #95. First of the v3.6.0 (Scheduling) milestone — and the correctness foundation the other three issues build on.
The bug
DateTimePickeremits a naive"YYYY-MM-DDTHH:MM"wall-clock string, and every submit path ran it throughnew Date(naive).toISOString()— which parses the string in the browser's zone. A GM whose browser zone differed from the campaign zone stored a different instant than the wall-clock time they typed, and every viewer then saw times in their own zone with no shared anchor.The backend and bot were already correct (UTC
DateTimecolumns; Discord<t:UNIX:F>dynamic timestamps that render per-viewer). So despite touching scheduling, the entire fix is frontend-side — confirmed by recon across all write/display/format paths.Approach — one tested helper, native
Intl, no new dependencysrc/utils/datetime.js. I deliberately did not adddate-fns-tz: the frontend has no date library, and I wasn't going to add one right after #105 cut the entry chunk 64%. Result: this whole fix adds ~0.25 kB (244.25 → 244.50 kB entry).zonedNaiveToUtcIso— campaign-zone wall-clock → UTC, DST-correct via a two-pass offset resolution. 19:00 campaign-time is a different UTC instant in summer vs winter, and the tests prove both.formatSessionTime/zoneShortLabel— render a stored UTC instant in the campaign zone with an explicit label (e.g. "Tue, Aug 4, 2026, 7:00 PM CDT"), so no displayed time is zone-ambiguous.viewerSecondaryTime— a "your time" line, only when the viewer's zone differs.Wired every scheduling site
<zone>)"; campaign settings upgraded to the fullIntl.supportedValuesOf('timeZone')list, plus an unset-zone nudge.Acceptance criteria
18:00with the campaign inAmerica/Chicagoand asserts23:00Z(CDT), not the host zone. Plus 22 helper tests with explicit-zone fixtures (host-independent).3:00 PM … CDT, secondary shows5:00 AMJST.new Date(naiveString).toISOString()on scheduling inputs — all five write sites converted.<t:>timestamps exclusively (nostrftimeanywhere inbot/).Milestone dates — the documented decision
Per the issue's point 5: milestone dates are floating calendar dates, anchored UTC-noon and displayed in UTC. This keeps the fix frontend-only (the column stays
DateTime) while making "the ball is on Aug 4" read Aug 4 for everyone.Verification
node:20 (matching CI):
npm run lint→ 0 problems (exhaustive-deps enforced);npx vitest run→ 129/129 (was 106; +22 helper, +1 display);npx vite build→ succeeds, entry chunk essentially unchanged.DST cases pinned by tests: America/Chicago summer (CDT/UTC-5) and winter (CST/UTC-6), Asia/Kolkata (UTC+5:30), Europe/Berlin both seasons, Pacific/Auckland, plus the fall-back overlap and spring-forward gap.
🤖 Generated with Claude Code