Module Time

Instants, durations, time zones, and civil date-times.

An Instant is a point on the timeline; a Duration is a signed span of nanoseconds. The difference of two instants is a duration (Since), and two instants can be ordered (Compare). A Zone maps instants to UTC offsets, and InZone projects an instant into a Zoned civil date-time for calendar work.

type Time.Duration = Int

A signed span of time, measured in nanoseconds.

Duration is just Int, so it supports the full integer algebra: add and subtract durations, multiply or divide by a number, negate, and compare them. Build durations from the unit constants, e.g. 5 * Time.Second or 2 * Time.Hour + 30 * Time.Minute.

type Time.Instant = iterative box choice {
  .add(Time.Duration) => self,
  .unixNanos => Int,
}

A point on the timeline, independent of any time zone.

  • .unixNanos — nanoseconds since the Unix epoch (1970-01-01T00:00:00Z).
  • .add(duration) — shift the instant by a duration, returning a new instant.

Differences and ordering are the free functions Since and Compare; civil fields come from projecting into a Zone with InZone.

type Time.Weekday = either {
  .friday!,
  .monday!,
  .saturday!,
  .sunday!,
  .thursday!,
  .tuesday!,
  .wednesday!,
}

A day of the week.

type Time.Zone = box choice {
  .name => String,
  .offsetAt(Time.Instant) => Time.Duration,
}

A time zone: a mapping from instants to UTC offsets.

  • .name — the zone's name (an IANA name like "Europe/Prague", or an offset like "+02:00" for fixed zones).
  • .offsetAt(instant) — the zone's UTC offset at the given instant, as a duration (it can vary across the year because of daylight saving time).
type Time.Zoned = iterative box choice {
  .addDays(Int) => self,
  .addMonths(Int) => self,
  .addYears(Int) => self,
  .day => Nat,
  .format(String) => String,
  .hour => Nat,
  .instant => Time.Instant,
  .minute => Nat,
  .month => Nat,
  .nanosecond => Nat,
  .second => Nat,
  .weekday => Time.Weekday,
  .year => Int,
  .zone => Time.Zone,
}

An instant seen through a time zone: a civil date-time with calendar fields.

  • .year — the year (can be negative for years before 1 CE).
  • .month — the month, 1 to 12.
  • .day — the day of the month, 1 to 31.
  • .hour — the hour, 0 to 23.
  • .minute — the minute, 0 to 59.
  • .second — the second, 0 to 59.
  • .nanosecond — the sub-second part, 0 to 999999999.
  • .weekday — the day of the week.
  • .zone — the time zone this date-time is in.
  • .instant — the underlying instant on the timeline.
  • .format(layout) — render using a strftime-style layout.
  • .addYears(n) — shift by whole years on the calendar, returning a new value.
  • .addMonths(n) — shift by whole months on the calendar.
  • .addDays(n) — shift by whole days on the calendar.

Calendar arithmetic (.addYears / .addMonths / .addDays) respects the zone, including daylight-saving transitions. For exact arithmetic on the timeline use Instant.add instead.

dec Time.At : [Time.Zone, Int, Nat, Nat, Nat, Nat, Nat] Option<Time.Zoned>

Builds a civil date-time in a zone from its calendar fields: At(zone, year, month, day, hour, minute, second). Returns .none! if the fields do not denote a valid date and time.

dec Time.Now : Time.Instant

The current instant, read from the system clock.

dec Time.Sleep : [Time.Duration] either {
  .elapsed!,
}

Sleeps for the given duration before resolving as .elapsed!. If the duration is negative or zero, resolves immediately.

Keep in mind that expressions evaluate concurrently in Par, so the following will NOT delay the printing of "Done":

let _ = Time.Sleep(Time.Second)
Debug.Log("Done")  // executes immediately, does not wait

To delay subsequent code/computation, it is necessary to tie it to the resolution of .elapsed! via .case:

Time.Sleep(Time.Second).case {
  .elapsed! => { Debug.Log("Done") }  // waits for 1 second
}

Or without nesting:

Time.Sleep(Time.Second).case { .elapsed! => {} }
Debug.Log("Done")

Or in an expression:

// "Done" printed after one second
let ! = do { Time.Sleep(Time.Second).case { .elapsed! => {} } } in Debug.Log("Done")
// but this code here executes immediately, does not wait