← All tests

Timezone hydration fix — nix-cafe STAGING

Pre-existing bug (predates the Khmer i18n work), surfaced by the i18n Gate-2 sweep. Verified on demo.staging 6/6 + i18n suite 6/6 + staging smoke 5/5.

The bug. lib/utils.ts formatDate() / formatTime() called toLocaleDateString/TimeString("en-US", …) with no timeZone, so they used the runtime's zone — the Cloudflare Worker renders in UTC while the browser renders in the user's local zone (ICT, UTC+7). Server HTML and client HTML therefore disagreed on every rendered time → React #418 ("Text content does not match server-rendered HTML"). Reproduced on the POS landing, whose register cards show session start/close times.

The fix. Pinned a shared APP_TIME_ZONE = "Asia/Phnom_Penh" (NIX Cafe is a Cambodia-only POS — times should be the shop's zone, not the viewer's browser). Applied to both helpers, which covers 32 call sites across 14 files, plus the remaining tz-less date renders (receipts, cash-movement dialog, kitchen live-clock, subscription, Odoo month label) and the dashboard weekday label (UTC-parsed + UTC-formatted, since it's a calendar date). 8 files, no migration.

Why it's safe

Cambodia users see no change — the browser already rendered ICT. Only the server's output changed (UTC → ICT) so the two now agree. Verified the same instant formats identically under three runtime zones:

TZ=UTC              → 06:30 AM | Jul 20, 2026   (the CF Worker / SSR)
TZ=Asia/Phnom_Penh  → 06:30 AM | Jul 20, 2026   (a Cambodia browser)
TZ=America/New_York → 06:30 AM | Jul 20, 2026   (a non-ICT browser)

Previously-mismatching pages — now zero hydration errors

POS landing
POS landing (was #418)
POS sessions
POS sessions
Orders
Orders
Team
Team (last login)
Customers
Customers

Checks (demo.staging, Pro)

POS landing — zero hydration errors (reproduced #418 before the fix)pass
POS sessions / Orders / Team / Customers — zero hydration errorspass
Same instant identical across UTC / ICT / non-ICT runtimespass
i18n suite re-run (no regression; hydration warnings now 0)6/6
Staging smoke5/5

nix-cafe staging ca4dadc (Worker nix-cafe-staging a614e798). If NIX ever goes multi-region, APP_TIME_ZONE is the single place to make per-tenant. Parked for the scheduled prod promote.