Practical frontend guide to Intl.DateTimeFormat and time zones: IANA zone IDs, daylight-saving transitions, formatToParts, and robust patterns for presenting user-local dates without fragile manual offset math.
JavaScript Intl.DateTimeFormat: Time Zones, DST, and Reliable Date Formatting
Use guided tracks for structured prep, then practice company-specific question sets when you want targeted interview coverage.
Definition (above the fold)
Use Intl.DateTimeFormat to render dates in the user or business time zone without manual offset arithmetic. The hard part is not formatting tokens. It is handling DST transitions, locale rules, and cross-region consistency. Interviewers want to hear why fixed offset math is unsafe in production apps.
Core mental model
Store timestamps in UTC, transport as ISO strings, and convert at the presentation edge with an IANA time zone (for example America/New_York). Do not store local wall-clock strings as source-of-truth.
Requirement | Recommended approach | Why |
|---|---|---|
Show user-local time | Intl.DateTimeFormat with user locale + zone | Correct locale grammar and DST handling |
Show business-region time | Pass explicit IANA zone in formatter options | Consistent cross-user display |
Build custom UI pieces | Use | Stable token extraction without brittle regex |
Sort/filter by time | Compare UTC timestamps, not formatted strings | Avoid locale-dependent ordering bugs |
Runnable example #1: stable zone-aware formatting
const ts = new Date('2026-03-08T09:30:00Z');
const fmt = new Intl.DateTimeFormat('en-US', {
timeZone: 'America/Los_Angeles',
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
hour12: false
});
console.log(fmt.format(ts));
This safely formats around DST boundaries without hardcoding offsets like UTC-8 or UTC-7.
Runnable example #2: formatToParts for composable UI
function formatParts(date, locale, timeZone) {
const parts = new Intl.DateTimeFormat(locale, {
timeZone,
weekday: 'short',
year: 'numeric',
month: 'short',
day: '2-digit',
hour: '2-digit',
minute: '2-digit'
}).formatToParts(date);
return Object.fromEntries(parts.map((p) => [p.type, p.value]));
}
console.log(formatParts(new Date(), 'en-GB', 'Europe/London'));
Pitfall | What goes wrong | Better pattern |
|---|---|---|
Fixed offset math | Breaks during DST transitions | Use IANA zone + Intl formatter |
Parsing localized strings | Inconsistent browser behavior | Parse ISO input, format only for output |
Using display value for data logic | Sorting/filtering bugs | Keep logic on numeric timestamps |
Assuming server timezone | Cross-region inconsistencies | Persist UTC and explicit zone metadata |
Common pitfalls
- Storing date-only values as midnight local time and getting off-by-one day bugs across regions.
- Rendering with browser default zone when product requirements need business-zone consistency.
- Testing only one locale/time zone and missing DST boundary regressions.
When to use / when not to use
Use Intl for display formatting in browser and server-rendered UI. Use timestamp math for calculations and persistence. Do not rely on manually concatenated date strings for mission-critical workflows like billing cutoffs or booking windows.
Interview follow-ups
Q1: Why avoid fixed offsets? A: Offsets change with DST and differ across historical periods.
Q2: How do you test this reliably? A: Add test cases around DST start/end for multiple IANA zones.
Q3: What do you store in database? A: UTC instant plus optional business-zone metadata when needed.
Implementation checklist / takeaway
Persist UTC, format with Intl + explicit IANA zones, validate DST edge cases in tests, and keep display concerns separate from business logic. Strong answers show both correctness and maintainability.