What Actually Happens at 2:00 AM on the First Sunday in November?

Published on May 26, 2026 by The Kestrel Tools Team • 7 min read

You’re debugging a payment system and notice two transactions logged at 2026-11-01T01:30:00 America/New_York. Same timestamp string. Different actual moments. One happened during Eastern Daylight Time, the other during Eastern Standard Time — sixty minutes apart. Your unix timestamp timezone conversion DST logic just silently ate an hour of data.

This isn’t a contrived edge case. Every system that stores local times hits this wall twice a year. The fix is straightforward once you understand the mechanism, but most developers learn it the hard way — usually at 3 AM during an incident.

Why Local Time Is Ambiguous (The “Fold” Problem)

When DST ends on the first Sunday in November, clocks “fall back” from 2:00 AM to 1:00 AM. The local times between 1:00 AM and 2:00 AM occur twice:

Wall clock timeFirst occurrence (EDT, UTC-4)Second occurrence (EST, UTC-5)
1:00:00 AMUTC 05:00:00UTC 06:00:00
1:30:00 AMUTC 05:30:00UTC 06:30:00
1:59:59 AMUTC 05:59:59UTC 06:59:59

This is called the “fold” — a period where the same local time string maps to two different instants. If your code stores 2026-11-01T01:30:00 without an offset or zone disambiguation, you’ve lost information permanently.

The spring transition has the opposite problem: a “gap.” When clocks jump forward from 2:00 AM to 3:00 AM, times like 2:30 AM simply don’t exist. Parsing 2026-03-08T02:30:00 America/New_York should throw an error — but many libraries silently clamp to 3:00 AM or 1:30 AM instead.

How Unix Timestamps Avoid the Ambiguity Entirely

A Unix timestamp is seconds since 1970-01-01T00:00:00Z. That “Z” is doing all the work — it anchors the count to UTC, which has no DST transitions. There is no fold, no gap, no ambiguity.

// These are the SAME local time string, different Unix timestamps
const firstOccurrence = 1793686200;  // 2026-11-01T01:30:00 EDT (UTC-4)
const secondOccurrence = 1793689800; // 2026-11-01T01:30:00 EST (UTC-5)

// Difference: exactly 3600 seconds (1 hour)
console.log(secondOccurrence - firstOccurrence); // 3600

This is why unix timestamp timezone conversion DST problems vanish when you store instants as epoch seconds: the conversion from “moment in time” to “display string” happens at read time, not write time. The timestamp itself is never ambiguous.

The Conversion Problem: Timestamp to Local Time

Going from Unix timestamp → local time is always safe. Every epoch second maps to exactly one local time in any timezone (even during the fold, because you already have the unambiguous instant).

Going the other direction — local time → Unix timestamp — is where bugs live:

// Ambiguous: which 1:30 AM?
new Date('2026-11-01T01:30:00'); // Depends on browser/runtime!

// Unambiguous: specify the offset
new Date('2026-11-01T01:30:00-04:00'); // EDT occurrence
new Date('2026-11-01T01:30:00-05:00'); // EST occurrence

// Also unambiguous: use Temporal (Stage 3)
Temporal.ZonedDateTime.from({
  year: 2026, month: 11, day: 1,
  hour: 1, minute: 30,
  timeZone: 'America/New_York',
  disambiguation: 'earlier' // or 'later', 'compatible', 'reject'
});

The disambiguation parameter is the key insight in the TC39 Temporal proposal. Instead of silently guessing, you declare what “1:30 AM” means when it’s ambiguous.

What Languages Actually Do During the Fold

Different runtimes handle the fold differently — and none of them warn you:

Language/RuntimeFold behavior (parsing ambiguous local time)Gap behavior
JavaScript DateImplementation-defined (usually picks the second occurrence)Rolls forward
Python datetimeNaive datetimes have no zone — fold is invisibleRaises on strict, rolls on lenient
Python zoneinfoRespects fold=0 (first) / fold=1 (second) attributeAdjusts based on fold
Java ZonedDateTimeUses “pre-transition offset” rule (picks first occurrence)Rolls forward
Go time.LoadLocationUses the earlier offset for ambiguous timesRolls forward
Rust chronoReturns MappedLocalTime::Ambiguous(earlier, later) — forces you to chooseReturns None for gaps

Rust’s chrono is the only mainstream library that makes the ambiguity visible at the type level. Every other language lets you write code that silently picks one interpretation without telling you it had a choice.

The Three Rules for DST-Safe Code

1. Store instants, not local times

Use Unix timestamps (epoch seconds/milliseconds) or ISO 8601 with an explicit offset (2026-11-01T01:30:00-05:00). Never store a bare local time for anything that represents “when something happened.”

2. Convert at the boundary

Format timestamps to local time only when displaying to users. Your database, your API responses, your event logs — all UTC or epoch. The conversion to America/New_York happens in the UI layer.

// API returns epoch
const timestamp = 1793689800;

// UI formats for display
const display = new Intl.DateTimeFormat('en-US', {
  timeZone: 'America/New_York',
  dateStyle: 'full',
  timeStyle: 'long'
}).format(new Date(timestamp * 1000));
// "Sunday, November 1, 2026 at 1:30:00 AM EST"

3. Test with fold and gap timestamps

Add these to your test suite:

// US 2026 fall-back: Nov 1, 2:00 AM → 1:00 AM
const foldTimestamp = 1793689800; // Second 1:30 AM (EST)

// US 2026 spring-forward: Mar 8, 2:00 AM → 3:00 AM
const gapTimestamp = 1741327800; // Would be 2:30 AM (doesn't exist)

If your formatter produces the same output for both occurrences of 1:30 AM, you have a display bug. If your parser doesn’t distinguish them, you have a data integrity bug.

Leap Seconds: The Other Time Lie

Unix time has a dirty secret: it pretends leap seconds don’t exist. UTC occasionally adds a second (the last one was December 31, 2016), but POSIX time defines every day as exactly 86400 seconds. When a leap second happens, Unix time either repeats a second or smears it across a window — depending on your OS and NTP configuration.

For most applications, this doesn’t matter. Payment processing at sub-second precision during a leap second? That matters. But leap seconds are being abolished by 2035 (per the CGPM resolution), so this is a shrinking concern.

Try It Yourself

Ready to verify your timestamps aren’t hiding a DST fold? Our Unix Timestamp Converter shows you the exact UTC moment behind any local time — including explicit offset display so you can spot ambiguity before it becomes an incident.

The Bottom Line

Timezone math isn’t hard because time is complex — it’s hard because local time is a lossy representation of an instant. Unix timestamps are lossless. Store instants, convert at display time, and test your fold/gap handling explicitly. Your on-call self at 2 AM in November will thank you.


Have questions about time handling or want to see more developer deep-dives? Follow us on X for practical dev content.