ADR-015 — Datetime: UTC Storage, Browser-Local Computation and Display
ADR-015 — Datetime: UTC Storage, Browser-Local Computation and Display
Sección titulada «ADR-015 — Datetime: UTC Storage, Browser-Local Computation and Display»Accepted
Context
Sección titulada «Context»The stack stores and transmits datetimes in UTC (USE_TZ=True, ISO 8601 Z suffix). There was no explicit rule for which timezone the frontend uses for temporal logic. A bug exposed this: isLateHour() used getUTCHours() while display showed browser local time — the user saw “19:40” flagged as out-of-hours because the logic evaluated 22:40 UTC.
Decision
Sección titulada «Decision»The user’s browser timezone is the sole basis for all computation and display in the frontend.
Stack layers.
| Layer | Rule |
|---|---|
| Django/PostgreSQL | USE_TZ = True. Every DateTimeField persisted in UTC. |
| DRF / API | Serializes ISO 8601 UTC with Z. No local offset accepted or returned. |
| Angular (display) | Converts UTC to browser-local time (toLocaleString, toLocaleDateString, toLocaleTimeString). |
| Angular (logic) | All temporal evaluation: browser-local methods (getHours(), getDay(), getDate()). Never getUTCHours() or any UTC variant. |
| Mock data | UTC with Z. Browser converts at render time, same as real API data. |
Clarification — Z and +00:00 are both valid. Both are valid ISO 8601 UTC representations. The API uses Z (per [[api-conventions|docs/stack/api-conventions.md]]), but the frontend must accept either. new Date("...Z") and new Date("...+00:00") produce the same instant — no special handling needed.
Cardinal rule.
[!important] If the user sees a time on screen, any logic that evaluates that time must operate in the same timezone as the display.
Future timezone override. If a user needs a timezone different from their browser’s, implement as a user preference (profile setting), not a global convention change.
Consequences
Sección titulada «Consequences»- All temporal logic in Angular uses local
Datemethods (getHours,getDay,getDate,getMonth), never UTC variants. - Display and logic are always in sync — what the user sees is what the code evaluates.
- Frontend tests involving times must account for the timezone of the machine running them.
- Django/API unchanged: UTC remains the transport and storage format.
- Mock data stays UTC with
Z; browser converts identically to real API data.