Daylight Saving Time Edge Cases
Why DST Breaks Software
Daylight Saving Time is a political decision, not a physical one. Governments decide when — or whether — to shift clocks. Rules change, exceptions appear, and some regions abolish DST entirely after decades of observance.
Your code needs to handle three categories of DST problems: timestamps that exist twice, timestamps that never exist, and durations that are not what you expect.
The Ambiguous Hour
When clocks fall back, one local time occurs twice.
2025-11-02 01:30:00 EDT (UTC-4)
2025-11-02 01:30:00 EST (UTC-5)
Both timestamps look identical in local time: 01:30. Without an offset or timezone identifier, you cannot tell which one a user means.
How it breaks code
// DANGEROUS: parsing without timezone context
const local = new Date('2025-11-02 01:30:00')
// Browser assumes the SECOND occurrence (EST) — but your user might mean the first (EDT)
How to handle it
Always store and compute in UTC. Convert to local time only for display. When a user enters 01:30 on a fall-back date, ask which occurrence they mean, or disambiguate using the IANA timezone database.
// Using Intl to check ambiguity
const tz = 'America/New_York'
const formatter = new Intl.DateTimeFormat('en-US', {
timeZone: tz,
year: 'numeric', month: '2-digit', day: '2-digit',
hour: '2-digit', minute: '2-digit', timeZoneName: 'short'
})
// Same wall time, two UTC equivalents
const edt = new Date('2025-11-02T05:30:00Z') // 01:30 EDT
const est = new Date('2025-11-02T06:30:00Z') // 01:30 EST
formatter.format(edt) // "11/02/2025, 1:30 AM EDT"
formatter.format(est) // "11/02/2025, 1:30 AM EST"
The Missing Hour
When clocks spring forward, one local time never exists.
2025-03-09 02:30:00 — this time does not exist in America/New_York
Clocks jump from 01:59:59 EST directly to 03:00:00 EDT. Any timestamp between 02:00 and 03:00 on that date is phantom.
How it breaks code
// User schedules a recurring event at 2:30 AM daily
// On March 9, that time does not exist
// Different systems handle this differently:
// - Some move it to 3:30 AM (spring forward)
// - Some move it to 1:30 AM (fall back)
// - Some silently drop the event
How to handle it
Validate user-input times against the IANA database. If a time falls in a gap, present a clear message: "This time does not exist on this date due to Daylight Saving Time. Please choose 1:30 AM or 3:30 AM."
Duration Shifts
A "24-hour" period does not always contain 24 hours in local time.
Spring forward: 23-hour day
March 9, 2025: 1:00 AM EST → March 10, 2025: 1:00 AM EDT = 23 hours
Fall back: 25-hour day
November 2, 2025: 1:00 AM EDT → November 3, 2025: 1:00 AM EST = 25 hours
How it breaks code
// WRONG: assuming 24 hours per day
const tomorrow = new Date(today.getTime() + 24 * 60 * 60 * 1000)
// On a spring-forward day, this lands on the SAME calendar date at 1:00 AM EDT
// instead of the next day's midnight
// CORRECT: use date arithmetic, not millisecond arithmetic
const tomorrow = new Date(today)
tomorrow.setDate(tomorrow.getDate() + 1)
For scheduling: always compute durations in UTC. Display in local time. A daily recurring event should be stored as "daily at 14:00 UTC" rather than "daily at 9:00 AM Eastern" — the latter shifts with DST.
International Edge Cases
The Southern Hemisphere
Countries below the equator observe DST in opposite months. Australia springs forward in October and falls back in April. If your team is in New York and your users are in Sydney, both hemispheres' transitions affect your application.
Regions that abolished DST
The European Union voted to abolish DST in 2019. Implementation has been delayed repeatedly. Your code should rely on the IANA database, not assumptions about which countries observe DST.
Notable non-observers:
- Japan (never observed)
- China (single timezone, no DST)
- India (no DST)
- Arizona (most of the state; the Navajo Nation does observe DST)
- Hawaii (no DST)
Last-minute rule changes
Brazil abolished DST in 2019, then reinstated it temporarily in 2021 during a power crisis. Russia moved between permanent summer time, permanent winter time, and back. Your timezone library must be updated regularly to track these changes.
Timezone Selection Anti-Patterns
| Anti-pattern | Why it fails | Correct approach |
|---|---|---|
| Hardcoding UTC offsets | Offsets change with DST | Use IANA identifiers |
Using abbreviations (EST, CST) | Ambiguous across regions | Use America/New_York, America/Chicago |
| Storing local time without timezone | Cannot reconstruct UTC | Store UTC + IANA timezone |
| Assuming DST dates are fixed | Governments change rules | Keep IANA database updated |
| Testing only summer dates | Misses fall-back ambiguities | Test both transition dates |
Key Takeaways
- DST creates ambiguous hours (fall back) and missing hours (spring forward) — always validate user input against the IANA database
- Store timestamps in UTC; convert to local time only for display
- Never assume days are 24 hours — use date arithmetic, not millisecond arithmetic
- Southern Hemisphere DST operates in opposite months — global apps must handle both
- Regions change DST rules without warning — keep your timezone library updated
- Always use IANA timezone identifiers, never abbreviations or hardcoded offsets
Related Guides
Try It Yourself
Convert times across DST boundaries safely with our free Timezone Converter. All conversions use IANA timezone data with automatic DST adjustment — no manual offset lookup needed.