std | |
time | |
calendar | |
calendars | Various calendars: TAI, GPS, ISO week, Julian, Coptic, etc. |
chrono | Get the system time. |
date | Date, clock, and week days support. |
duration | Time durations in SI seconds. |
format | Formatting of time into a string. |
instant | Instants in time. |
locale | Localization of time formats. |
parse | Parsing of time strings. |
time | Time represents instants as human readable calendar time. |
timer | High resolution timer. |
utc | UTC time scales and leap second support. |
This is an extensive library for managing time.
By using careful defaults the library offers an easy to use interface for the
common use cases, but uses accurate and precise time representations and algorithms.
In particular, it handles accurate leap seconds, time zones, multiple calendars,
and astronomical time scales.
Internally time is represented by a 128-bit ddoublestd/num/ddouble/ddouble: V
giving it a very high range
and precision (up to 31 decimal digits, see the std/time/instantstd/time/instant
module for more
information). As such, we believe this library is one of the most accurate time
libraries around.
Core concepts are:
A durationstd/time/duration/duration: V
is a span of time in SI seconds (as measured on the earth's geoid).
An instantstd/time/instant/instant: V
represents an instant in time. Instants can be substracted to
get the durationstd/time/duration/duration: V
between them. Instants are usually represented as the number
of fractional SI seconds since the epochstd/time/instant/epoch: instant
(2000-01-01Z), but can be represented
in different time scales for efficiency. For example, there is the TAI time scale (ts-taistd/time/instant/ts-tai: timescale
),
standard UTC (ts-tistd/time/utc/ts-ti: timescale
), or astronomical time scales like terrestrial time (std/time/astrostd/time/astro
).
A timestd/time/time/time: V
is a human readable datestd/time/date/date: V
(year, month, day), and clockstd/time/date/clock: V
(hour, minutes, seconds)
in a particular calendarstd/time/calendar/calendar: V
(usually the standard ISO calendar) and time zone.
Instants can be converted to time values and back. We can add logical years, months, or
days to a timestd/time/time/time: V
, or get the difference between times in days etc. See the
std/time/timestd/time/time
module for more information.
The current time, in the UTC timezone (tz-utcstd/time/calendar/tz-utc: timezone
) using the ISO calendar (cal-isostd/time/calendar/cal-iso: calendar
):
> time-now().show "2017-01-30T15:40:25.367000103Z" > time-now().show "2017-01-30T15:40:25.367000103Z"
Or the current time in the local timezone:
> local-time-now().show "2017-01-30T07:59:01.693000078-08:00 (PST)" > local-time-now().show "2017-01-30T07:59:01.693000078-08:00 (PST)"
We can also get the current instant in time as the number of SI seconds since the epochstd/time/instant/epoch: instant
:
> now() 539106063.980999947s > nowstd/time/chrono/now: () -> <ndet,utc> instant() 539106063.980999947s
See std/time/chronostd/time/chrono
for more information on system time.
Calendar times can be constructed by giving a year, month (1-based), and day of the month (1-based)
and optional hour, minutes, seconds, fraction of the second, timezone (tz-utcstd/time/calendar/tz-utc: timezone
) and
calendar (cal-isostd/time/calendar/cal-iso: calendar
):
> time(2000,1,1).show "2000-01-01T00:00:00Z" > time(2000,1,1).show "2000-01-01T00:00:00Z"
Instants can be constructed similarly, and can be converted to and from
timestd/time/time/time: V
values. Here we construct a time value interpreted in
the TAI time scale (which was 32 seconds ahead of UTC on 2000-01-01Z):
> instant(2000,1,1).time(cal=cal-tai).show "2000-01-01T00:00:32Z TAI" > instant(2000,1,1).time(cal=cal-tai).show "2000-01-01T00:00:32Z TAI"
The cal-tai
calendar is the standard ISO calendar but uses the TAI time scale (ts-taistd/time/instant/ts-tai: timescale
)
instead of UTC time.
The library takes much care to correctly handle leap seconds and time zone transitions. For example, here are some durations between different times:
> (time(2016,1,1,0,0,0,0.5) - time(2015,12,31,23,59,59)).show "1.5s" > (time(2017,1,1,0,0,0,0.5) - time(2016,12,31,23,59,59)).show "2.5s" // over a leap second > (time(2017,1,1,0,0,0,0.5) - time(2017,1,1,2,59,59,tz=tz-fixed(3)).show "2.5s" // UTC+3, and over a leap second > (time(2016,1,1,0,0,0,0.5) - time(2015,12,31,23,59,59)).show "1.5s" > (time(2017,1,1,0,0,0,0.5) - time(2016,12,31,23,59,59)).show "2.5s" // over a leap second > (time(2017,1,1,0,0,0,0.5) - time(2017,1,1,2,59,59,tz=tz-fixedstd/time/calendar/tz-fixed: (hours : int, mins : ? int, name : ? string, abbrv : ? string, hourwidth : ? int) -> timezone(3)).show "2.5s" // UTC+3, and over a leap second
Similarly, adding logical days (or weeks, months, or years) works over leap seconds and other time irregularties:
> time(2016,12,31,12).add-days(1).show "2017-01-01T12:00:00Z" // over a leap second > time(1582,10,4,cal=cal-jg).add-days(1).show "1582-10-15T00:00:00Z JG" // transition from Julian (`cal-julian`) to Gregorian (`cal-gregorian`) calendar) > time(2016,12,31,12).add-days(1).show "2017-01-01T12:00:00Z" // over a leap second > time(1582,10,4,cal=cal-jgstd/time/calendars/cal-jg: calendar).add-days(1).show "1582-10-15T00:00:00Z JG" // transition from Julian (`cal-julian`) to Gregorian (`cal-gregorian`) calendar)
See the utc
module for more information on leap seconds.
If calculating with timezones besides the UTC (tz-utcstd/time/calendar/tz-utc: timezone
)
and local timezone (tz-localstd/time/calendar/tz-local: () -> ndet timezone
), one needs to use the std/time/timezonestd/time/timezone
module to load the latest time zone information (load-timezones
).
import std/time import std/time/timezone fun test-timezones() { val tzs = load-timezones() val tz1 = tzs.timezone("America/New_York") val tz2 = tzs.timezone("Pacific/Kosrae") /* A flight of 12.5 hours from New York to Kosrae */ val t1 = instant(1997,12,31,12,1,0,tz=tz1) + (12.hours + 30.minutes) t1.time(tz=tz2).show.println // "1998-01-01T17:31:00+12:00" /* Again, but across DST & leap second */ val t2 = instant(1998,12,31,12,1,0,tz=tz1) + (12.hours + 30.minutes) t2.time(tz=tz2).show.println // "1999-01-01T16:30:59+11:00" } import std/timestd/time import std/time/timezonestd/time/timezone fun test-timezones() { val tzs = load-timezones() val tz1 = tzs.timezone("America/New_York") val tz2 = tzs.timezone("Pacific/Kosrae") /* A flight of 12.5 hours from New York to Kosrae */ val t1 = instant(1997,12,31,12,1,0,tz=tz1) + (12.hours + 30.minutes) t1.time(tz=tz2).show.println // "1998-01-01T17:31:00+12:00" /* Again, but across DST & leap second */ val t2 = instant(1998,12,31,12,1,0,tz=tz1) + (12.hours + 30.minutes) t2.time(tz=tz2).show.println // "1999-01-01T16:30:59+11:00" }
Using the nowstd/time/chrono/now: () -> <ndet,utc> instant
or time-now
for measuring time intervals is not appropriate since these functions
are not guaranteed to be monotonic or of sufficiently high precision. For timing, the std/time/timerstd/time/timer
module
should be used with functions like ticksstd/time/timer/ticks: () -> ndet duration
or elapsedstd/time/timer/elapsed: forall<a,e> (action : () -> <ndet|e> a) -> <ndet|e> (duration, a)
:
import std/time/timer fun nfib(n : int) : int { if (n <= 1) then 1 else 1 + nfib(n - 1) + nfib(n - 2) } fun test-nfib() { print-elapsed{ nfib(30) } // "elapsed 0.111s" } import std/time/timerstd/time/timer fun nfib(n : intstd/core/types/int: V) : intstd/core/types/int: V { if (n <= 1) then 1 else 1 + nfib(n - 1) + nfib(n - 2) } fun test-nfib() { print-elapsedstd/time/timer/print-elapsed: forall<a,e> (action : () -> <ndet,console|e> a, msg : ? string) -> <ndet,console|e> a{ nfib(30) } // "elapsed 0.111s" }
The library uses by default the International Time (TI) time scale (ts-tistd/time/utc/ts-ti: timescale
) which
uses UTC time with leap seconds up to 2019, and ignores leap seconds after
this. This is a nice default as it tracks historical leap seconds precisely
while having deterministic future time calculations. Moreover, even if there
are future leap seconds, only durations calculations between times will be
off by the inserted leap seconds; time-now
, timestd/time/time/time: V
, and instants
stay valid and designate correct times (as they use a day + seconds
internal representation).
There are two other good UTC time scales though:
ts-ti-slsstd/time/utc/ts-ti-sls: timescale
smooths leap seconds over the last 1000s of a day with a leap
second so they never appear in any displayed time or timestamp.
ts-utc-createstd/time/utc/ts-utc-create: (leaps : leaps-table) -> timescale
/cal-utc-load
creates a proper UTC timescale from a leap
second table. This ensures future leap seconds are fully accounted for and
that duration calculations work properly up to 6 months into the future.
~begin htmlraw
Calendars.