moondate
MoonBit · dates & schedules

Dates, times, and the schedule behind them.

Parse and format RFC 3339, HTTP and ASN.1 timestamps. Keep the four kinds of moment apart. Ask a cron expression when it fires next — every answer comes from the calendar's arithmetic, not a lookup table.

$ moon add moonbitstack/moondate
moondate · live
shape Zoned canon 2026-09-22T14:30:00+08:00 format Tuesday, 22 September 2026
4
shapes a moment can take
1ns
resolution of clocks and spans
6
cron fields, seconds optional
0
lookup tables — the calendar is arithmetic
The four shapes

One moment, four meanings.

TOML names exactly these, and the difference is not decoration. Only Zoned is an instant; the other three need a zone before they can name one.

instant

Zoned

An instant. Has an epoch, and can be read in another zone.

2026-09-22T14:30:00Z
wall clock

Plain

An alarm, an opening time. No zone, so no epoch yet.

2026-09-22T14:30:00
date

Day

A date with no time of day.

2026-09-22
time

Clock

A time with no date.

14:30:00
What it does

A calendar, and the text around it.

The calendar is the proleptic Gregorian one, exact over the whole range an integer holds. Everything else is about reading and writing it in the forms the wire expects.

Parse & format

Read a timestamp into one of four shapes, and write it back in the shape it was. A round trip through a document keeps every field.

Calendar arithmetic

Days, weekdays, year days, ISO week dates and ordinals. Add days or months and carry across boundaries without a table.

HTTP dates

Write the one form a Date header may take, and read the two obsolete forms a recipient must still accept.

ASN.1 time

UTCTime and GeneralizedTime, with the two-digit-year window a certificate uses — which is not the window HTTP uses.

strftime & strptime

The C89 directives, in both directions, so a format string reads back exactly what it wrote.

cron

Five fields, or six with seconds. Names, lists, ranges, steps and the shorthands — plus the answer to when it next fires.

Reads and writes

The forms a timestamp travels in.

FormWhere it is used
RFC 3339 / ISO 8601JSON, TOML, and most of the wire
IMF-fixdate · RFC 850 · asctimeHTTP's Date header — all three read, IMF-fixdate written
UTCTime · GeneralizedTimeASN.1, and so an X.509 certificate's validity
strftime / strptimeThe C89 directives, both ways
Schedules

Ask a cron expression when it fires next.

Five fields as crontab(5) defines them, or six with seconds in front. Both 0 and 7 are Sunday. Day-of-month and day-of-week are or-ed when both are restricted.

cron

next firings

schedule.mbt
let now = @moondate.parse("2026-09-22T14:30:00Z")
@cron.parse("0 9 * * MON-FRI").next(now)   // Some(2026-09-23T09:00:00Z)
@cron.parse("@daily").next(now)            // Some(2026-09-23T00:00:00Z)
the next weekday at nine, after 2026-09-22T14:30Z2026-09-23T09:00:00Z