Time Library (Time)
Every timestamp in this library is a plain ms value (nanoseconds for the _ns variants) — which means normal unit arithmetic just works on them. Time.diff(start) as seconds reads naturally instead of needing a manual division.
Current Time & Elapsed
now() -> ms
The current Unix timestamp, in milliseconds.
#[main]
fn main() {
pln(Time.now());
}now_ns() -> ns
Same idea, in nanoseconds — for when millisecond resolution isn't fine enough.
#[main]
fn main() {
pln(Time.now_ns());
}diff(prev: float) -> ms
Shorthand for Time.now() - prev — how much time has passed since a timestamp you captured earlier.
#[main]
fn main() {
const ts = Time.now();
sleep(50ms);
pln(Time.diff(ts) >= 50);
}diff_ns(prev: float) -> ns
The nanosecond version of diff.
#[main]
fn main() {
const ts = Time.now_ns();
sleep(50ms);
pln(Time.diff_ns(ts) >= 49ms);
}sleep(time: float = 1000ms) -> void
An alias for Std.sleep — identical behavior, just callable through Time for anyone who'd rather keep every time-related call under one namespace.
#[main]
fn main() {
const ts = Time.now();
Time.sleep(50ms);
pln(Time.diff(ts) >= 50);
}Formatting
RFC 3339 is the ISO-8601-flavored format most APIs use today; RFC 2822 is the older, email-header-style format — both convert cleanly to and from a plain ms timestamp.
now_rfc3339() -> str
#[main]
fn main() {
pln(Time.now_rfc3339());
}now_rfc2822() -> str
#[main]
fn main() {
pln(Time.now_rfc2822());
}to_rfc3339(time: float) -> str
#[main]
fn main() {
pln(Time.to_rfc3339(Time.now()));
}to_rfc2822(time: float) -> str
#[main]
fn main() {
pln(Time.to_rfc2822(Time.now()));
}from_rfc3339(time: str) -> ms
#[main]
fn main() {
const ts = Time.from_rfc3339("2025-08-13T16:22:43.028375200+00:00");
pln(ts < Time.now());
}from_rfc2822(time: str) -> ms
#[main]
fn main() {
const ts = Time.from_rfc2822("Wed, 13 Aug 2025 16:24:12 +0000");
pln(ts < Time.now());
}Reading Components
All UTC — none of these read a local timezone.
year(ts: ms) -> int
#[main]
fn main() {
pln(Time.year(Time.now()));
}month(ts: ms) -> int
1–12.
#[main]
fn main() {
pln(Time.month(Time.now()));
}day_of_month(ts: ms) -> int
1–31.
#[main]
fn main() {
pln(Time.day_of_month(Time.now()));
}day_of_week(ts: ms) -> int
ISO convention — 0 is Monday, 6 is Sunday.
#[main]
fn main() {
pln(Time.day_of_week(Time.now()));
}hour(ts: ms) -> int
0–23.
#[main]
fn main() {
pln(Time.hour(Time.now()));
}minute(ts: ms) -> int
#[main]
fn main() {
pln(Time.minute(Time.now()));
}second(ts: ms) -> int
#[main]
fn main() {
pln(Time.second(Time.now()));
}days_in_month(ts: ms) -> int
28–31, leap years handled correctly for February.
#[main]
fn main() {
pln(Time.days_in_month(Time.now()));
}Calendar Arithmetic
add_days(ts: ms, n: int) -> ms
n can be negative.
#[main]
fn main() {
const tomorrow = Time.add_days(Time.now(), 1);
pln(tomorrow > Time.now());
}add_months(ts: ms, n: int) -> ms
If the day of month doesn't exist in the target month, it clamps to the last valid day — Jan 31 plus one month lands on Feb 28 (or 29).
#[main]
fn main() {
const next = Time.add_months(Time.now(), 1);
pln(next > Time.now());
}Period Boundaries
Every start_of_* function returns midnight UTC on the relevant boundary — useful for anything that resets on a schedule.
start_of_day(ts: ms) -> ms
#[main]
fn main() {
pln(Time.start_of_day(Time.now()) <= Time.now());
}start_of_week(ts: ms, start_day: int = 0) -> ms
start_day follows the same ISO convention as day_of_week — 0 is Monday by default, but any day can be the week's start.
#[main]
fn main() {
const mon_start = Time.start_of_week(Time.now());
const sun_start = Time.start_of_week(Time.now(), 6);
pln(mon_start <= Time.now(), sun_start <= Time.now());
}start_of_month(ts: ms) -> ms
#[main]
fn main() {
const som = Time.start_of_month(Time.now());
pln(Time.day_of_month(som));
}start_of_year(ts: ms) -> ms
#[main]
fn main() {
const soy = Time.start_of_year(Time.now());
pln(Time.month(soy), Time.day_of_month(soy));
}start_of_period(ts: ms, schedule: str) -> ms
The most flexible of the five — a schedule expression instead of a fixed unit. Returns null for an invalid schedule string:
"monthly:N"— the Nth day of every month (clamped to the month's length)"monthly:last"— the last day of every month"weekly:mon"— a given weekday, every week (mon/tue/wed/thu/fri/sat/sun)"nth_weekday:N:mon"— the Nth occurrence of a weekday in the month (Nis 1–4)"yearly:M-D"— a fixed month and day every year"quarterly:D"— a given day of the first month of each quarter (Jan/Apr/Jul/Oct)
#[main]
fn main() {
pln(Time.start_of_period(Time.now(), 'monthly:1') <= Time.now());
pln(Time.start_of_period(Time.now(), 'weekly:mon') <= Time.now());
pln(Time.start_of_period(Time.now(), 'nth_weekday:1:tue') <= Time.now());
pln(Time.start_of_period(Time.now(), 'yearly:1-1') <= Time.now());
pln(Time.start_of_period(Time.now(), 'quarterly:1') <= Time.now());
}