Timezone and Date Handling Review Workflow
Audit storage, display, and computation of times, standardize on UTC with explicit zones at the edges, and test around DST and month boundaries.
Objective
Eliminate timezone bugs by reviewing how dates are stored, transmitted, and displayed.
Environment
- Access to the data model and UI code
- Test data spanning DST transitions
Steps
1. Verify timestamps are stored in UTC
Verify timestamps are stored in UTC with an explicit type.
Expected state: Storage is unambiguous.
2. Check that APIs transmit ISO 8601
Check that APIs transmit ISO 8601 with offset or Z.
Expected state: The wire format carries the zone.
3. Convert to the user zone only
Convert to the user zone only at display, never in storage.
Expected state: Computation is consistent across users.
4. Test around DST transitions, month ends,
Test around DST transitions, month ends, and leap days.
Expected state: Edge cases are handled.
Decision points
Store local time or UTC?
- UTC
- Local with a zone column
UTC for instants; store a separate zone only when the wall-clock time matters (like a recurring alarm).
Use naive date libraries?
- A zone-aware library
- Native date only
Use a zone-aware library; native date handling of zones and DST is a common bug source.
Expected outcome
Dates stored and transmitted in UTC with explicit zones, converted at display, and verified across DST and calendar boundaries.
Verification
Confirm that a test spanning a DST transition shows the right local time and that no stored timestamp lacks a zone.
Cleanup
Record the standard and update the developer guide.
Overview
Eliminate timezone bugs by reviewing how dates are stored, transmitted, and displayed. Confirm that a test spanning a DST transition shows the right local time and that no stored timestamp lacks a zone.
Steps
- Verify timestamps are stored in UTC with an explicit type. Expected state: Storage is unambiguous.
- Check that APIs transmit ISO 8601 with offset or Z. Expected state: The wire format carries the zone.
- Convert to the user zone only at display, never in storage. Expected state: Computation is consistent across users.
- Test around DST transitions, month ends, and leap days. Expected state: Edge cases are handled.
// store UTC, convert at display
const instant = new Date().toISOString(); // 2026-10-23T12:00:00Z
const local = new Intl.DateTimeFormat('en-GB', { timeZone: userTz, timeStyle: 'short' }).format(new Date(instant));
Verification
- Dates stored and transmitted in UTC with explicit zones, converted at display, and verified across DST and calendar boundaries.
Decision points
- Store local time or UTC? Options: UTC; Local with a zone column. Recommended: UTC for instants; store a separate zone only when the wall-clock time matters (like a recurring alarm).
- Use naive date libraries? Options: A zone-aware library; Native date only. Recommended: Use a zone-aware library; native date handling of zones and DST is a common bug source.