How do I work with Unix timestamps in EK9?

← Date, Time, and Duration · Ref: Q543

EK9 uses the Millisecond type for epoch-based timestamps, and DATE LITERALS plus typed arithmetic for epoch dates - there is no untyped 'number of days' constructor to reach for.

GETTING EPOCH TIME

  epochNow <- SystemClock().millisecond()

This returns a Millisecond: the unit travels WITH the value, so it cannot be confused for seconds or nanoseconds.

THE EPOCH IS A LITERAL

  unixEpoch <- 1970-01-01

Write the date you mean. A bare Integer cannot say which unit it is in, so EK9 does not offer one here.

DISTANCE BETWEEN DATES IS SUBTRACTION

  sinceEpoch <- y2k - unixEpoch

Date - Date yields a Duration, and that Duration is a CALENDAR SPAN - P30Y for 1970-01-01 to 2000-01-01 - not a flat day count. Duration does expose days(), months() and years(), but those project the span onto a nominal 30-day month, so days() reads 10800 here rather than the 10957 real days. Use them for magnitude, not as an exact count.

GOING BACK THE OTHER WAY

  rebuilt <- unixEpoch + sinceEpoch

Date + Duration yields a Date, and because the span kept its calendar structure the round trip back to Y2K is EXACT. Note that EK9 date arithmetic is CALENDAR-AWARE, so a Duration is not simply a day count - see Q550.

MILLISECOND AS TIMESTAMP

Millisecond is the natural type for Unix timestamps, API timestamps and database epoch values, and supports arithmetic directly.

See Q41 for Millisecond basics. See Q544 for benchmarking. See Q536 for the current date and time. See Q550 for calendar-aware date arithmetic.

Example

defines module qa.unix.timestamps

  defines program
    UnixTimestampsDemo()
      stdout <- Stdout()

      // Epoch time as a TYPED Millisecond - the unit travels with the value
      epochNow <- SystemClock().millisecond()
      stdout.println(`Epoch now: ${epochNow}`)

      // The epoch is just a date LITERAL. EK9 has no Date(Integer): a bare number
      // cannot say whether it means days, seconds or a year.
      unixEpoch <- 1970-01-01
      stdout.println(`Epoch date: ${unixEpoch}`)

      y2k <- 2000-01-01
      stdout.println(`Y2K: ${y2k}`)

      // 'How far apart are two dates' is subtraction, and the answer is a CALENDAR
      // SPAN - years/months/days - not a flat count of days
      sinceEpoch <- y2k - unixEpoch
      stdout.println(`Y2K since the epoch: ${sinceEpoch}`)

      // days() projects that span onto a nominal 30-day month, so it is an
      // APPROXIMATION - use it for magnitude, not as an exact day count
      stdout.println(`Approx days, 30-day months: ${sinceEpoch.days()}`)

      // Date + Duration goes back the other way, and because the span kept its
      // calendar structure the round trip is exact
      rebuilt <- unixEpoch + sinceEpoch
      stdout.println(`Round-trips to Y2K: ${rebuilt == y2k}`)

      // Millisecond to Duration conversion
      fiveSeconds <- 5000ms
      asDuration <- fiveSeconds.duration()
      stdout.println(`5000ms as Duration: ${asDuration}`)

      // Millisecond arithmetic for timestamp differences
      earlier <- SystemClock().millisecond()
      stdout.println("Some work here")
      later <- SystemClock().millisecond()
      elapsed <- later - earlier
      stdout.println(`Elapsed is set: ${elapsed?}`)

Common mistakes

E50060 — SystemClock has no currentTimeMillis() method. Use millisecond() to get the current epoch time as a typed Millisecond value. See ek9 -h E50060 for details.

Incorrect:

epochNow <- SystemClock().currentTimeMillis()

Correct:

epochNow <- SystemClock().millisecond()
Other ways to ask this
  • How do I convert epoch milliseconds to a date?
  • How do I get the Unix epoch time in EK9?
  • How does Millisecond relate to epoch time?
  • How do I work with epoch time in EK9?

Coming from another language?

Java: System.currentTimeMillis(), LocalDate.ofEpochDay()/toEpochDay(). Python: time.time(), date.fromordinal() (note: ordinal counts from year 1, not 1970). JavaScript: Date.now(), new Date(epochMs). Go: time.Now().UnixMilli(). Rust: SystemTime::now().duration_since(UNIX_EPOCH). EK9: SystemClock().millisecond() returns a typed Millisecond; the epoch is the literal 1970-01-01; distances are Date - Date -> Duration. EK9 deliberately has no Date(Integer) - a bare number cannot state its unit.

Keywords: millisecond, time, timezone, days, unix, systemclock, epoch, seconds, duration, timestamp, convert