Kite

time

std/time — the clock, and what to say about it.

time.now() is a compiler builtin: it reads the runtime's clock in milliseconds. The clock is virtual on the bytecode VM and in the generated glue — when every task is waiting on a deadline it jumps to the earliest — so a program that sleeps costs no real time under test and both backends agree on the order things happened in.

seconds

pub fn seconds(n: int) -> int

Milliseconds in one second.

minutes

pub fn minutes(n: int) -> int

hours

pub fn hours(n: int) -> int

millis

pub fn millis(n: int) -> int

since

pub fn since(start: int) -> int

How long since a reading taken earlier.

show

pub fn show(ms: int) -> str

A duration in the largest unit that keeps it readable.

clock

pub fn clock(ms: int) -> str

hh:mm:ss from a duration, for a stopwatch or a progress line.

Civil

struct Civil

A moment, split the way a person reads one.

civil_of

pub fn civil_of(ms: int, east_minutes: int) -> Civil

Split an epoch reading into fields.

ms is milliseconds since 1970-01-01T00:00:00Z — what window.epoch_ms() answers, and not what time.now() answers, which is a monotonic reading with no zero point a calendar could use.

let at = civil_of(1_754_697_600_000, 0)
assert(at.year == 2025 && at.month == 8 && at.day == 9, "2025-08-09")

epoch_of

pub fn epoch_of(c: Civil, east_minutes: int) -> int

Put one back together.

The inverse of [civil_of] under the same offset. Fields outside their range are carried rather than refused — month 13 is January of the next year, and day 0 is the last day of the month before — which is what makes Civil{ year: y, month: m + 1, day: 1, … } a correct way to ask for the start of the next month without knowing how long this one is.

iso_day

pub fn iso_day(ms: int, east_minutes: int) -> str

YYYY-MM-DD, which is what a filename wants.

A folder of reports named "10 Jul 2026" sorts April before January. This one sorts in the only order that is unambiguous in every locale.

assert(iso_day(1_754_697_600_000, 0) == "2025-08-09", "a day, written out")

hhmm

pub fn hhmm(ms: int, east_minutes: int) -> str

hh:mm from a moment, for a status bar with no room for a date.

Distinct from [clock] one section up, which reads a duration — the two print the same shape from different numbers, and giving them one name would make the difference invisible at the call site.

stamp

pub fn stamp(ms: int, east_minutes: int) -> str

YYYY-MM-DDThh:mm:ss, without an offset suffix.

The suffix is left off because this renders in whatever zone was asked for and appending Z to a local reading is a lie a log keeps forever. A caller who wants a true RFC 3339 timestamp passes 0 and adds the Z itself.

weekday

pub fn weekday(ms: int, east_minutes: int) -> int

The day of the week: 0 is Sunday, 6 is Saturday.

is_leap

pub fn is_leap(year: int) -> bool

Whether a year has a 29th of February.

days_in_month

pub fn days_in_month(year: int, month: int) -> int

How many days are in a month, 1 to 12.

Counted as the distance between two firsts rather than read out of a table with a leap-year branch beside it. The table and the branch can disagree; two calls to the same function cannot.

month_start

pub fn month_start(year: int, month: int, east_minutes: int) -> int

The first millisecond of a month.

month outside 1 to 12 is carried, so month_start(y, 13, e) is January of the following year — which is how [month_end] finds the boundary without asking how long the month it is ending happens to be.

month_end

pub fn month_end(year: int, month: int, east_minutes: int) -> int

The last millisecond that still belongs to a month.

Inclusive, so a query written >= month_start(…) and <= month_end(…) cannot let the midnight between two months fall into both or into neither.