Module time/instant
The two clocks: Instant (monotonic, for measuring elapsed time) and
SystemTime (wall clock, for timestamps that outlive the process).
They are deliberately DIFFERENT TYPES and not interconvertible. A monotonic reading has no meaning outside this process — it cannot be persisted, compared across machines, or turned into a date — while a wall-clock reading can jump backwards when the system clock is adjusted and so must never be used to measure a duration. Rust draws the same line, and mixing them is the bug the split prevents.
Example
{ Instant, SystemTime, UNIX_EPOCH } :: import("std/time/instant");
start := Instant.now();
// ... do work ...
println(start.elapsed().as_millis()); // elapsed: monotonic
t := SystemTime.now();
match(t.duration_since(UNIX_EPOCH), // timestamp: wall clock
.Ok(d) => println(d.as_secs()),
.Err(e) => println(e)
);
Stability
unstable — SystemTime arrived in v0.2.28 (#522) and has had one release,
and two shapes here still differ from Rust in ways that a caller can only
discover by reading the body. Instant.duration_since and Instant.sub
CLAMP at zero, where Rust's Instant::duration_since panics on a later
argument and splits the non-panicking cases into checked_duration_since
and saturating_duration_since; the clamp is defensible for a monotonic
clock but it silently turns a reversed-argument bug into a zero. Neither
type has the checked_add/checked_sub Rust offers, Instant has no
Hash or Default while Duration has both, and SystemTime has no
ToString/Debug — a timestamp that cannot be printed. Instant.add/
sub also multiply out to a nanosecond count, which is exactly what the
SystemTime helpers below were written to avoid; it is harmless only
because a monotonic reading is uptime rather than a date.
Freezing needs the clamp-vs-checked_* split decided and those trait gaps
filled. The two-clock division itself is settled and will not move.
Types
Snapshot from the monotonic clock. Use elapsed to measure durations.
Fields
| Name | Type | Description |
|---|---|---|
secs | i64 | Whole seconds since the Unix epoch. Negative before 1970. |
nanos | i64 | Sub-second part, always in |
Trait Implementations
impl(Instant, ...)
now : (Instant) fn() -> InstantRead the monotonic clock — Rust's Instant::now.
Panics if clock_gettime(CLOCK_MONOTONIC) fails, rather than returning
a zero: a broken clock must not read as "the beginning of time", which
would make every subsequent elapsed() enormous
(plans/archive/STD_API_AUDIT.md C10).
Returns: Instant
duration_since : (Instant) fn(inout(self) : Instant, earlier : Instant) -> DurationHow much later self is than earlier.
CLAMPS to Duration.zero() when earlier is actually the later of the
two, rather than panicking as Rust's Instant::duration_since does — so
a reversed pair of arguments reads as "no time passed" instead of
failing. A monotonic clock cannot itself run backwards, so a zero here
means the arguments were the wrong way round.
Parameters
| Name | Type | Notes |
|---|---|---|
self | Instant | |
earlier | Instant |
Returns: Duration
impl(Instant, ...)
add : (Instant) fn(inout(self) : Instant, d : Duration) -> Instantimpl(Instant, Eq(Instant)(...))
impl(Instant, Ord(Instant)(...))
Methods
clone : (Instant) fn(inout(self) : Instant) -> Instant== : (Instant) fn(lhs : Instant, rhs : Instant) -> bool!= : (Instant) fn(lhs : Instant, rhs : Instant) -> bool< : (Instant) fn(lhs : Instant, rhs : Instant) -> bool<= : (Instant) fn(lhs : Instant, rhs : Instant) -> bool> : (Instant) fn(lhs : Instant, rhs : Instant) -> bool>= : (Instant) fn(lhs : Instant, rhs : Instant) -> boolRaised when a SystemTime comparison runs backwards.
Not a theoretical case: the system clock can be stepped by NTP or by hand,
so a timestamp taken later can precede one taken earlier. Rust returns a
Result from duration_since/elapsed for exactly this, and returning a
silent Duration.zero() instead — the way Instant.duration_since may,
since a monotonic clock cannot go backwards — would hide a real clock jump.
Variants
| Variant | Fields | Description |
|---|---|---|
EarlierThan | by: Duration |
|
Trait Implementations
Methods
to_string : (SystemTimeError) fn(inout(self) : SystemTimeError) -> Stringsource : (SystemTimeError) fn(inout(self) : SystemTimeError) -> Option(dyn(ToString + ))The error that caused this one, or .None at the root of the chain.
Rust's Error::source. Defaulted to .None, so an error with nothing
underneath it implements the trait by saying only what it is; a wrapper
overrides it to hand back what it wrapped. Walking the chain to the root
cause works as of 2026-09-14 — the returned Dyn used to lose the
Error trait on an erased receiver, so a caller could print one link but
not follow it (#521,
issues/fixed/self-trait-in-a-return-type-loses-the-trait-on-an-erased-receiver.md).
Parameters
| Name | Type | Notes |
|---|---|---|
self | SystemTimeError |
A wall-clock timestamp, measured from UNIX_EPOCH.
Use this for anything that leaves the process — a file's mtime, a log line,
a serialized record. Use Instant to MEASURE, never this: the wall clock
can jump.
Fields
| Name | Type | Description |
|---|---|---|
secs | i64 | Whole seconds since the Unix epoch. Negative before 1970. |
nanos | i64 | Sub-second part, always in |
Trait Implementations
impl(SystemTime, ...)
now : (SystemTime) fn() -> SystemTimeRead the wall clock. Panics if CLOCK_REALTIME fails, for the same
reason Instant.now does: a broken clock must not silently read as the
epoch.
Returns: SystemTime
from_unix_secs : (SystemTime) fn(secs : i64) -> SystemTimeA timestamp from whole seconds since the epoch — what a stat field or
a serialized record carries.
Parameters
| Name | Type | Notes | Description |
|---|---|---|---|
secs | i64 | Whole seconds since the Unix epoch. Negative before 1970. |
Returns: SystemTime
from_unix_parts : (SystemTime) fn(secs : i64, nanos : i64) -> SystemTimeA timestamp from seconds plus a nanosecond part. nanos outside
[0, 1e9) is carried into secs, so a caller need not pre-normalize;
OS timestamp fields already supply a value in range.
Parameters
| Name | Type | Notes | Description |
|---|---|---|---|
secs | i64 | Whole seconds since the Unix epoch. Negative before 1970. | |
nanos | i64 | Sub-second part, always in |
Returns: SystemTime
as_unix_secs : (SystemTime) fn(inout(self) : SystemTime) -> i64Whole seconds since the epoch, truncating the sub-second part.
Parameters
| Name | Type | Notes |
|---|---|---|
self | SystemTime |
Returns: i64
duration_since : (SystemTime) fn(inout(self) : SystemTime, earlier : SystemTime) -> Result(Duration, SystemTimeError)How much later self is than earlier, or .Err when it is EARLIER —
which means the clock was adjusted between the two readings.
Parameters
| Name | Type | Notes |
|---|---|---|
self | SystemTime | |
earlier | SystemTime |
Returns: Result(Duration, SystemTimeError)
elapsed : (SystemTime) fn(inout(self) : SystemTime) -> Result(Duration, SystemTimeError)How long ago self was, or .Err if it is in the future.
Parameters
| Name | Type | Notes |
|---|---|---|
self | SystemTime |
Returns: Result(Duration, SystemTimeError)
add : (SystemTime) fn(inout(self) : SystemTime, d : Duration) -> SystemTimesub : (SystemTime) fn(inout(self) : SystemTime, d : Duration) -> SystemTimeimpl(SystemTime, Eq(SystemTime)(...))
impl(SystemTime, Ord(SystemTime)(...))
Methods
clone : (SystemTime) fn(inout(self) : SystemTime) -> SystemTime== : (SystemTime) fn(lhs : SystemTime, rhs : SystemTime) -> bool!= : (SystemTime) fn(lhs : SystemTime, rhs : SystemTime) -> bool< : (SystemTime) fn(lhs : SystemTime, rhs : SystemTime) -> bool<= : (SystemTime) fn(lhs : SystemTime, rhs : SystemTime) -> bool> : (SystemTime) fn(lhs : SystemTime, rhs : SystemTime) -> bool>= : (SystemTime) fn(lhs : SystemTime, rhs : SystemTime) -> boolcmp : (SystemTime) fn(lhs : SystemTime, rhs : SystemTime) -> OrderingConstants
1970-01-01T00:00:00Z — the anchor SystemTime is measured from.
Value: SystemTime(secs: 0, nanos: 0)