time
Time capability implementation using platform time functions.
Implements the Time capability typeclass for real clock access, plus direct helpers (sleep-ms / get-time-ms / get-cpu-time).
Not auto-loaded -- import the names you need explicitly:
(import time :refer [sleep-ms get-time-ms])
Since: Phase 16
Time
(defopaque Time :ptr<void>)
opaque handle to a Time capability struct (now/sleep closures).
Created by Real-Time / HighRes-Time / Mock-Time; released by the matching *-free helper.
Since: Phase 16
Real-Time
(Real-Time :Time)
create a wall-clock Time capability.
A heap-allocated Time struct with: now -- returns milliseconds since the Unix epoch, read the way now-ms reads it (CLOCK_REALTIME; millisecond precision). sleep -- sleeps for the requested number of milliseconds via nanosleep, retrying on EINTR. Free with Real-Time-free when done.
(let [t (Real-Time)] ...)
Since: Phase 16
Real-Time-free
(Real-Time-free [t :Time] :void)
release a Time capability created by Real-Time.
| t | the Time pointer returned by Real-Time. |
Since: Phase 16
HighRes-Time
(HighRes-Time :Time)
create a CPU-clock Time capability backed by clock().
A heap-allocated Time struct with: now -- returns CPU time in milliseconds (based on CLOCKS_PER_SEC). sleep -- sleeps for the requested number of milliseconds via nanosleep. Note: now measures CPU time, not wall-clock time. Free with HighRes-Time-free when done.
(let [t (HighRes-Time)] ...)
Since: Phase 16
HighRes-Time-free
(HighRes-Time-free [t :Time] :void)
release a Time capability created by HighRes-Time.
| t | the Time pointer returned by HighRes-Time. |
Since: Phase 16
Mock-Time
(Mock-Time :Time)
create a controllable Time capability for testing.
A heap-allocated Time struct backed by an internal integer counter (initially 0 ms). now returns the current counter value; sleep advances the counter by the requested amount without blocking. Use mock-time-set and mock-time-get to inspect and manipulate time. Each Mock-Time keeps its own clock, so several can be live at once. Free with Mock-Time-free when done.
(let [t (Mock-Time)] (mock-time-set t 5000) ...)
Since: Phase 16
Mock-Time-free
(Mock-Time-free [t :Time] :void)
release a Time capability created by Mock-Time.
| t | the Time pointer returned by Mock-Time. |
Since: Phase 16
mock-time-set
(mock-time-set [t :Time new_time :int] :void)
set the current time on a Mock-Time instance.
| t | the Mock-Time pointer. | |
| new_time | the new time value in milliseconds. |
(mock-time-set t 10000) ; set mock clock to 10 seconds
Since: Phase 16
mock-time-get
(mock-time-get [t :Time] :int)
read the current time from a Mock-Time instance.
| t | the Mock-Time pointer. |
The current mock time in milliseconds as an int.
(mock-time-get t) ; => 10000
Since: Phase 16
now-ms
(now-ms)
the current wall-clock time in milliseconds since the Unix epoch.
Reads CLOCK_REALTIME (GetSystemTimePreciseAsFileTime on Windows), so the value has real millisecond resolution. Wall-clock time can jump (NTP, a user changing the clock); measure durations with monotonic-ns. Spelled time/now-ms under a plain (import time).
Milliseconds since 1970-01-01T00:00:00Z as an int.
(time/now-ms) ; => 1791158400123
Since: stdlib-os-surface P0
monotonic-ns
(monotonic-ns)
a monotonic clock reading in nanoseconds, for durations.
Never goes backwards and is unaffected by wall-clock changes. The origin is arbitrary (typically boot), so only the difference between two readings is meaningful. CLOCK_MONOTONIC on POSIX, QueryPerformanceCounter on Windows. Spelled time/monotonic-ns under a plain (import time).
Nanoseconds since an unspecified fixed origin, as an int.
(let [t0 (time/monotonic-ns)] (work) (- (time/monotonic-ns) t0))
Since: stdlib-os-surface P0
get-time-ms
(get-time-ms :int)
return the current wall-clock time in milliseconds since epoch.
The historical spelling of now-ms, with the same real millisecond resolution (it used to be time(NULL) * 1000 -- one-second steps behind a millisecond name).
Milliseconds since the Unix epoch as an int.
(get-time-ms) ; => 1747123456789
Since: Phase 16
sleep-ms
(sleep-ms [ms :int] :void)
suspend execution for a given number of milliseconds.
| ms | number of milliseconds to sleep (no-op if <= 0). |
(sleep-ms 250) ; sleep for a quarter second
Since: Phase 16
get-cpu-time
(get-cpu-time :int)
return the current process CPU time in milliseconds.
clock() * 1000 / CLOCKS_PER_SEC -- CPU milliseconds consumed by the current process.
(get-cpu-time) ; => 42 (42 ms of CPU time used so far)
Since: Phase 16
DateTime
(defstruct DateTime [])
a calendar date and time of day, with its UTC offset.
Fields:
year -- the full year, e.g. 2026 (proleptic Gregorian; may be <= 0)
month -- 1-12
day -- 1-31
hour -- 0-23
minute -- 0-59
second -- 0-59 (60 only when parsed from a leap-second timestamp)
millis -- 0-999
offset -- minutes east of UTC that the other fields are expressed in:
0 from utc-parts, the zone's offset from local-parts
(e.g. 120 for UTC+2, -300 for UTC-5)
A plain :copy value: build one with (DateTime y mo d h mi s ms offset), read a field with (.year dt). datetime->ms turns it back into an instant.
Since: stdlib-os-surface P3
utc-parts
(utc-parts [ms :int] :DateTime)
the UTC calendar fields of an instant.
Pure arithmetic: no time-zone lookup. Spelled time/utc-parts under a plain (import time).
| ms | milliseconds since the Unix epoch, as now-ms answers them | |
| (negative for instants before 1970) |
A DateTime with offset 0.
(.year (time/utc-parts 0)) ; => 1970
Since: stdlib-os-surface P3
local-parts
(local-parts [ms :int])
the local-time calendar fields of an instant.
Uses the process's time zone (TZ, else the system's; re-read on every call) through localtime_r -- localtime_s on Windows -- including daylight saving in force at that instant. When the platform cannot convert the instant (Windows refuses times before 1970) the answer is utc-parts's. Spelled time/local-parts under a plain (import time).
| ms | milliseconds since the Unix epoch |
A DateTime whose offset is the zone's offset from UTC at ms, in minutes east (so datetime->ms gives ms back).
(.offset (time/local-parts (time/now-ms))) ; => 120 in UTC+2
Since: stdlib-os-surface P3
datetime->ms
(datetime->ms [dt :DateTime] :int)
the instant a DateTime names, in epoch milliseconds.
The inverse of utc-parts and local-parts: the fields are read in the DateTime's own offset. Out-of-range fields are not rejected; they carry (minute 90 is an hour and a half). Spelled time/datetime->ms under a plain (import time).
| dt | the DateTime |
Milliseconds since the Unix epoch.
(time/datetime->ms (DateTime 1970 1 2 0 0 0 0 0)) ; => 86400000
Since: stdlib-os-surface P3
format-iso8601
(format-iso8601 [dt :DateTime] :cstr)
an ISO 8601 / RFC 3339 timestamp for a DateTime.
YYYY-MM-DDTHH:MM:SS, then .mmm when millis is not 0, then Z for offset 0 or +HH:MM / -HH:MM. A year outside 0-9999 is written in the expanded form, signed and at least six digits (+010000-01-01T...). parse-iso8601 reads every string this writes.
| dt | the DateTime |
A fresh heap cstr the caller owns (release with free).
(time/format-iso8601 (time/utc-parts 1500)) ; => "1970-01-01T00:00:01.500Z"
Since: stdlib-os-surface P3
parse-iso8601
(parse-iso8601 [s :cstr] :(Option DateTime))
read an ISO 8601 / RFC 3339 timestamp.
Accepts YYYY-MM-DD (midnight UTC), or that followed by T (or t, or a space) and HH:MM, optional :SS, optional .fraction (or ,fraction; digits past milliseconds are dropped), then an optional zone: Z, +HH:MM, +HHMM or +HH (a missing zone is read as UTC). The year may be the signed expanded form format-iso8601 writes. Every field is range checked, including the day against its month.
| s | the timestamp text |
(Some dt) with the offset the text gave, or None when s is not a valid timestamp.
(time/parse-iso8601 "2026-10-21T09:30:00+02:00") ; => (Some dt) with hour 9, offset 120
Since: stdlib-os-surface P3
Internal definitions
days-from-civil-- days since 1970-01-01 of a calendar date (internal).parse-iso8601-raw-- the parse, with month 0 for a rejected string (internal).