principlejavascriptMajor
UTC vs local time — store UTC, display local
Viewed 0 times
UTClocal timeDSTdate arithmetictimezone conversion
Problem
Developers confuse when to store/process in UTC versus when to use local time, leading to off-by-one day bugs, incorrect comparisons, and DST gaps.
Solution
Store and transmit in UTC. Display in local time.
const now = Date.now(); // UTC epoch milliseconds
new Date().toISOString(); // UTC string
// Display in user's timezone
new Intl.DateTimeFormat('en-US', {
timeZone: userTimezone,
}).format(new Date(utcTimestamp));
// Arithmetic: ms is safe for hours and below
const inOneHour = new Date(Date.now() + 3_600_000);
const now = Date.now(); // UTC epoch milliseconds
new Date().toISOString(); // UTC string
// Display in user's timezone
new Intl.DateTimeFormat('en-US', {
timeZone: userTimezone,
}).format(new Date(utcTimestamp));
// Arithmetic: ms is safe for hours and below
const inOneHour = new Date(Date.now() + 3_600_000);
Why
UTC has no DST, no ambiguous times, and allows correct global comparisons. Converting to local time only at display time keeps logic simple and correct.
Gotchas
- Adding 86400 seconds to a local time can skip or duplicate an hour across DST transitions
- Date.now() is always UTC epoch milliseconds — the safest primitive to use
- getHours() returns local hours, getUTCHours() returns UTC hours — be explicit
- SQL TIMESTAMP WITHOUT TIME ZONE is a footgun — use TIMESTAMP WITH TIME ZONE
Code Snippets
UTC storage and local display
// Always compare UTC
const a = new Date('2024-03-10T00:00:00Z').getTime();
const b = new Date('2024-03-11T00:00:00Z').getTime();
const diffDays = (b - a) / 86_400_000; // 1
// Display in user's timezone
new Intl.DateTimeFormat('en-US', {
timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone,
dateStyle: 'medium',
}).format(new Date(a));Revisions (0)
No revisions yet.