Documentation / Core packages / Core time

Core time

@core/time separates monotonic elapsed time from UTC wall-clock time. Many APIs blur these domains, which makes duration measurements vulnerable to clock changes. Moth gives each domain an opaque type.

Choose the explanation level: Time helpers

Time helpers

@core/time separates elapsed time from wall-clock time. Bind it when you need to measure durations or work with UTC timestamps.

Three types of time

  • Duration for elapsed amounts
  • TimeMark for measuring elapsed time and frame deltas
  • Timestamp for real-world UTC instants

These types stay opaque. Pass them to the package functions. Do not construct them with struct syntax.

Measuring elapsed time

Use TimeMark for a monotonic measurement point. Use Duration for the elapsed amount.

@core/time TimeMark, mark_now, duration_between, as_seconds

previous ~= mark_now()

current = mark_now()
delta = duration_between(previous, current)
previous = current

seconds = as_seconds(delta)

This shape works for frame-delta style code without requiring a scheduler or animation package.

UTC timestamps

Use Timestamp for real-world UTC instants that may be logged, stored or exchanged with external systems.

@core/time Timestamp, timestamp_from_iso_string, timestamp_from_unix_milliseconds, to_iso_string

parse_created || -> Timestamp, Error!:
    return timestamp_from_iso_string("1970-01-01T00:00:00.000Z")!
;

created = parse_created() catch:
    then timestamp_from_unix_milliseconds(0.0)
;

io.line(to_iso_string(created))

timestamp_from_iso_string takes the fallible path because invalid strings can fail. Handle it with ! or catch. For the full function list, backend behaviour and deferred surfaces, see Core time advanced.

@core/time separates elapsed time from wall-clock time. It belongs to the binding-backed Core package family with no prelude alias, so it requires an explicit dependency clause.

@core/time carries Core origin with ExternalBinding backing. See Package origins and backing for origin and backing rules.

Dependency roots

Bind individual symbols or the whole namespace:

@core/time Duration, TimeMark, mark_now, duration_between, as_seconds

@core/time

previous = time.mark_now()

Opaque types

The package exposes three opaque types. Do not construct them with struct syntax or inspect their fields. Pass them to the package functions.

Type

Purpose

Duration

Signed elapsed amount

TimeMark

Monotonic clock mark for deltas and frame timing

Timestamp

UTC wall-clock instant for logs, storage and system boundaries

All three use the handle ABI. They carry no source-visible fields.

Monotonic clock functions

Function

Parameters

Returns

Error

mark_now()

none

TimeMark

no

elapsed_since(start)

TimeMark

Duration

no

duration_between(start, end)

TimeMark, TimeMark

Duration

no

mark_now() returns the current monotonic mark. elapsed_since(start) returns the duration from start to now. duration_between(start, end) returns the duration from start to end.

Wall-clock timestamp functions

Function

Parameters

Returns

Error

timestamp_now()

none

Timestamp

no

timestamp_from_unix_seconds(seconds)

Float

Timestamp

no

timestamp_from_unix_milliseconds(milliseconds)

Float

Timestamp

no

timestamp_from_iso_string(text)

String

Timestamp, Error!

yes

timestamp_from_iso_string is the only fallible function. Invalid ISO strings return through Error!.

@core/time Timestamp, timestamp_from_iso_string, timestamp_from_unix_milliseconds

created = timestamp_from_iso_string("not-a-date") catch:
    then timestamp_from_unix_milliseconds(0.0)
;

Duration construction and helpers

Function

Parameters

Returns

Error

duration_from_seconds(seconds)

Float

Duration

no

duration_from_milliseconds(milliseconds)

Float

Duration

no

as_seconds(duration)

Duration

Float

no

as_milliseconds(duration)

Duration

Float

no

is_negative(duration)

Duration

Bool

no

abs(duration)

Duration

Duration

no

clamp(duration, min, max)

Duration, Duration, Duration

Duration

no

Timestamp helpers

Function

Parameters

Returns

Error

unix_seconds(timestamp)

Timestamp

Float

no

unix_milliseconds(timestamp)

Timestamp

Float

no

to_iso_string(timestamp)

Timestamp

String

no

Access and return contracts

All parameters use shared access. No function requires mutable access. All return values stay fresh. timestamp_from_iso_string returns through Error! on invalid input. Every other function stays infallible.

Backend behaviour

HTML-JS lowers mark_now to globalThis.performance.now(). timestamp_now lowers to Date.now(). to_iso_string lowers to (new Date(#0)).toISOString(). Duration and timestamp construction helpers lower to inline JavaScript expressions.

HTML-Wasm lacks a Wasm lowering for these functions. See progress matrix for current target availability.

Unsupported source forms

  • Direct symbol-path clauses such as @core/time/mark_now face rejection. Use direct selections or a namespace clause.
  • Named arguments are not supported. Binding-backed calls are positional-only.
  • Do not construct Duration, TimeMark or Timestamp with struct syntax.
  • Do not inspect opaque type fields directly.
  • The package does not expose receiver methods.

Deferred surfaces

Calendar date types, time zones, local-time conversion, locale-aware formatting, timers, sleep, intervals, animation callbacks and non-JS lowerings remain deferred. Browser animation-frame integration belongs in a future web-specific package rather than @core/time. See progress matrix for current status.

Related concepts