What are common timezone mistakes and how does EK9 prevent them?

← Date, Time, and Duration · Ref: Q553

Six common timezone mistakes and how EK9 addresses each one.

1. STORING LOCAL TIME WITHOUT TIMEZONE

Mistake: saving '2024-06-15 10:30' without specifying which timezone.
Java: LocalDateTime has no timezone, stored values are ambiguous.
EK9: DateTime always carries a timezone. You cannot create a DateTime without one. Literals require Z or an offset.

2. COMPARING NAIVE AND AWARE DATETIMES

Mistake: comparing a timezone-unaware timestamp with a timezone-aware one.
Python: raises TypeError when mixing naive and aware datetimes.
EK9: all DateTimes are timezone-aware. Comparison automatically normalizes to UTC (see Q548).

3. CONFUSING withSameInstant AND withZone
Mistake: using the wrong conversion method, creating a DateTime that represents a different moment than intended.
Java: withZoneSameInstant() vs withZoneSameLocal() have confusing names.
EK9: withSameInstant() and withZone() have clear, descriptive names (see Q546).

4. ASSUMING FIXED UTC OFFSETS

Mistake: hardcoding UTC-5 for New York (fails during daylight saving time).
EK9: use IANA names like 'America/New_York' which automatically handle DST transitions.

5. IGNORING DST IN ARITHMETIC

Mistake: adding 24 hours and expecting to land on the same time tomorrow (fails on DST transition days).
EK9: Duration arithmetic on DateTime handles DST correctly. Adding P1D adds one calendar day regardless of DST.

6. USING AMBIGUOUS TIMEZONE ABBREVIATIONS

Mistake: using 'EST' (could be US Eastern or Australian Eastern).
EK9: IANA names are unambiguous. 'America/New_York' and 'Australia/Sydney' are distinct.

See Q541 for timezone basics. See Q545 for timezone conversion. See Q546 for withSameInstant vs withZone. See Q547 for UTC storage. See Q548 for cross-timezone comparison.

Example

defines module qa.timezone.mistakes

  defines constant
    newYorkZone <- "America/New_York"

  defines program
    TimezoneMistakesDemo()
      stdout <- Stdout()

      // MISTAKE 1: EK9 DateTimes always have a timezone
      // You cannot create an ambiguous timestamp
      utcEvent <- 2024-06-15T10:30:00Z
      offsetEvent <- 2024-06-15T10:30:00-04:00
      stdout.println(`UTC: ${utcEvent}, zone: ${utcEvent.zone()}`)
      stdout.println(`Offset: ${offsetEvent}, zone: ${offsetEvent.zone()}`)

      // MISTAKE 2: All comparisons normalize to UTC
      // No mixing naive and aware - everything is aware
      require utcEvent <> offsetEvent
      stdout.println(`Different instants: ${utcEvent <> offsetEvent}`)

      // MISTAKE 3: Clear method names
      // withSameInstant = same moment, different display
      nyDisplay <- utcEvent.withSameInstant(newYorkZone)
      stdout.println(`Same instant NY: ${nyDisplay}`)
      require nyDisplay == utcEvent

      // withZone = same clock, different moment
      nyLabel <- utcEvent.withZone(newYorkZone)
      stdout.println(`Same clock NY: ${nyLabel}`)
      require nyLabel <> utcEvent

      // MISTAKE 4: Use IANA names, not fixed offsets
      // newYorkZone handles DST automatically
      summer <- 2024-06-15T12:00:00Z
      winter <- 2024-12-15T12:00:00Z
      nySummer <- summer.withSameInstant(newYorkZone)
      nyWinter <- winter.withSameInstant(newYorkZone)
      stdout.println(`NY summer offset: ${nySummer.zone()}`)
      stdout.println(`NY winter offset: ${nyWinter.zone()}`)

      // MISTAKE 5: Duration arithmetic is calendar-safe
      beforeDST <- 2024-03-09T12:00:00-05:00
      plusOneDay <- beforeDST + P1D
      stdout.println(`Before DST: ${beforeDST}`)
      stdout.println(`+ P1D: ${plusOneDay}`)

      // MISTAKE 6: IANA names are unambiguous
      usEast <- utcEvent.withSameInstant(newYorkZone)
      auEast <- utcEvent.withSameInstant("Australia/Sydney")
      stdout.println(`US Eastern: ${usEast}`)
      stdout.println(`AU Eastern: ${auEast}`)

Common mistakes

E50060 — DateTime has no withZoneSameInstant() method (that is the Java naming). EK9 uses the clearer name withSameInstant(). See ek9 -h E50060 for details.

Incorrect:

nyDisplay <- utcEvent.withZoneSameInstant(newYorkZone)

Correct:

nyDisplay <- utcEvent.withSameInstant(newYorkZone)
Other ways to ask this
  • What timezone bugs does EK9 prevent?
  • How does EK9 handle daylight saving time?
  • What are the most common timezone errors in programming?

Coming from another language?

All languages have timezone pitfalls. Java: LocalDateTime loses timezone, ZonedDateTime methods have confusing names. Python: naive vs aware datetimes, pytz normalize() gotcha. JavaScript: Date has no timezone awareness beyond local/UTC. Go: time.Location is opaque, DST handled internally. EK9: all DateTimes carry timezone, IANA names, clear method names, UTC-normalized comparison.

Keywords: mistake, offset, naive, migrate, iana, aware, daylight saving, prevention, dst, bug, timezone, duration, time