How do I compare DateTimes across different timezones in EK9?
← Date, Time, and Duration · Ref: Q548
EK9 automatically normalizes DateTimes to UTC for comparison. Two DateTimes representing the same instant are always equal, regardless of their timezone labels.
AUTOMATIC UTC NORMALIZATION
utcNoon <- 2024-06-15T12:00:00Z nyMorning <- 2024-06-15T08:00:00-04:00 require utcNoon == nyMorning
Both represent 12:00 UTC. The comparison sees through the timezone difference.
ALL COMPARISON OPERATORS NORMALIZE
This works for ==, <>, <, >, <=, >=, <=>:
require 2024-06-15T12:00:00Z < 2024-06-15T09:00:00-04:00 (12:00 UTC < 13:00 UTC)
SORTING WORKS CORRECTLY
A collection of DateTimes from different timezones sorts by their actual chronological order, not by clock reading.
DURATION SUBTRACTION ALSO NORMALIZES
gap <- 2024-06-15T14:00:00-04:00 - 2024-06-15T12:00:00Z
The gap is the actual elapsed time between the two instants, accounting for timezones.
WHY THIS MATTERS
In JavaScript, comparing Date objects from different timezone strings is unreliable. In some databases, comparing TIMESTAMP WITHOUT TIME ZONE columns across regions gives wrong results. EK9 eliminates this entire category of bugs by always comparing the underlying UTC instant.
See Q541 for timezone basics. See Q542 for general date comparison. See Q545 for timezone conversion. See Q553 for common timezone mistakes.
Example
defines module qa.compare.across.timezones defines program CompareAcrossTimezonesDemo() stdout <- Stdout() // Same instant, different timezones utcNoon <- 2024-06-15T12:00:00Z nyMorning <- 2024-06-15T08:00:00-04:00 tokyoEvening <- 2024-06-15T21:00:00+09:00 // All represent 12:00 UTC require utcNoon == nyMorning require utcNoon == tokyoEvening require nyMorning == tokyoEvening stdout.println(`UTC noon == NY 8am: ${utcNoon == nyMorning}`) stdout.println(`UTC noon == Tokyo 9pm: ${utcNoon == tokyoEvening}`) // Different instants, different timezones laterUTC <- 2024-06-15T14:00:00Z require laterUTC > nyMorning require laterUTC > tokyoEvening stdout.println(`14:00 UTC > 08:00 NY: ${laterUTC > nyMorning}`) // Spaceship operator also normalizes ordering <- nyMorning <=> tokyoEvening require ordering == 0 stdout.println(`NY <=> Tokyo: ${ordering}`) // Duration subtraction normalizes event1 <- 2024-06-15T10:00:00-04:00 event2 <- 2024-06-15T16:00:00+02:00 // event1 = 14:00 UTC, event2 = 14:00 UTC gap <- event2 - event1 stdout.println(`Gap: ${gap}`) require event1 == event2 // Collection of DateTimes from different timezones times as List of DateTime := [laterUTC, nyMorning, utcNoon] unsetDt <- DateTime() firstTime <- times.getOrDefault(0, unsetDt) lastIdx <- length times - 1 lastTime <- times.getOrDefault(lastIdx, unsetDt) stdout.println(`First: ${firstTime}`) stdout.println(`Last: ${lastTime}`)
Common mistakes
E50060 — DateTime has no isEqual() method. EK9 uses the == operator directly, which automatically normalizes both sides to UTC before comparing. See ek9 -h E50060 for details.
Incorrect:
require utcNoon.isEqual(nyMorning)
Correct:
require utcNoon == nyMorning
Other ways to ask this
- Do timezone differences affect DateTime comparison?
- How does EK9 handle comparing UTC and local times?
- Are DateTimes normalized before comparison?
Coming from another language?
Java: ZonedDateTime.isEqual() compares instants correctly, but == compares object identity (wrong). Python: timezone-aware datetimes compare correctly, but mixing naive and aware raises TypeError. JavaScript: Date comparison uses UTC internally but timezone string parsing is inconsistent. Go: time.Equal() normalizes, but == does not (compares location too). EK9: all comparison operators automatically normalize to UTC.
Keywords: migrate, instant, across, compare, duration, normalize, utc, equal, time, timezone, different