How do I convert a DateTime to a different timezone in EK9?

← Date, Time, and Duration · Ref: Q545

Use withSameInstant(zoneId) to convert a DateTime to show the same moment in a different timezone. This is the most common timezone operation.

CONVERTING FOR DISPLAY

  utcEvent <- 2024-06-15T14:00:00Z
  nyDisplay <- utcEvent.withSameInstant('America/New_York')
  tokyoDisplay <- utcEvent.withSameInstant('Asia/Tokyo')
  londonDisplay <- utcEvent.withSameInstant('Europe/London')

All three represent the SAME moment. Only the clock reading and timezone label change.

COMMON IANA ZONE NAMES

  Americas: America/New_York, America/Chicago, America/Denver, America/Los_Angeles, America/Sao_Paulo
  Europe: Europe/London, Europe/Paris, Europe/Berlin, Europe/Moscow
  Asia: Asia/Tokyo, Asia/Shanghai, Asia/Kolkata, Asia/Dubai
  Pacific: Australia/Sydney, Pacific/Auckland
  UTC: UTC, Etc/UTC

PATTERN: STORE UTC, DISPLAY LOCAL

Store all timestamps in UTC. Convert to the user's timezone only for display:

  stored <- 2024-06-15T14:00:00Z
  userZone <- 'America/New_York'
  displayed <- stored.withSameInstant(userZone)

This avoids timezone confusion in comparisons and arithmetic.

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

Example

defines module qa.convert.timezone

  defines program
    ConvertTimezoneDemo()
      stdout <- Stdout()

      // UTC event
      utcEvent <- 2024-06-15T14:00:00Z
      stdout.println(`UTC: ${utcEvent}`)

      // Convert to various timezones
      nyTime <- utcEvent.withSameInstant("America/New_York")
      chicagoTime <- utcEvent.withSameInstant("America/Chicago")
      laTime <- utcEvent.withSameInstant("America/Los_Angeles")
      londonTime <- utcEvent.withSameInstant("Europe/London")
      parisTime <- utcEvent.withSameInstant("Europe/Paris")
      tokyoTime <- utcEvent.withSameInstant("Asia/Tokyo")
      sydneyTime <- utcEvent.withSameInstant("Australia/Sydney")

      stdout.println(`New York: ${nyTime}`)
      stdout.println(`Chicago: ${chicagoTime}`)
      stdout.println(`Los Angeles: ${laTime}`)
      stdout.println(`London: ${londonTime}`)
      stdout.println(`Paris: ${parisTime}`)
      stdout.println(`Tokyo: ${tokyoTime}`)
      stdout.println(`Sydney: ${sydneyTime}`)

      // All are the same instant
      require nyTime == utcEvent
      require tokyoTime == utcEvent
      require sydneyTime == utcEvent
      stdout.println(`All equal UTC: ${nyTime == utcEvent and tokyoTime == utcEvent}`)

      // Store UTC, display local pattern
      stored <- 2024-12-25T00:00:00Z
      userZone <- "Europe/Berlin"
      displayed <- stored.withSameInstant(userZone)
      stdout.println(`Stored: ${stored}`)
      stdout.println(`User sees: ${displayed}`)

Common mistakes

E50060 — DateTime has no convertTo() method. Use withSameInstant() to convert a DateTime to show the same moment in a different timezone. See ek9 -h E50060 for details.

Incorrect:

nyTime <- utcEvent.convertTo("America/New_York")

Correct:

nyTime <- utcEvent.withSameInstant("America/New_York")
Other ways to ask this
  • How do I display a time in a different timezone?
  • How do I convert UTC to local time in EK9?
  • How does withSameInstant work for timezone conversion?

Coming from another language?

Java: dateTime.withZoneSameInstant(ZoneId.of('America/New_York')). Python: dt.astimezone(zoneinfo.ZoneInfo('America/New_York')). JavaScript: no built-in, Intl.DateTimeFormat for display only. Go: t.In(loc). Rust: chrono with_timezone(). EK9: dateTime.withSameInstant('America/New_York') clear and concise.

Keywords: timezone, local, zone, duration, convert, display, time, iana, withSameInstant, utc