moondate
Playground · Winter

Run it here.

The library compiled to JavaScript and running in this page. Change an input and the answer updates — parsed and formatted, the next firings of a schedule, or the local time in six cities at once. Nothing is pre-computed, and the zone data is the IANA release itself.

01

Parse & format

style
shape Zoned canon 2026-09-22T14:30:00+08:00 format Tuesday, 22 September 2026

The shape line is read from the text: an offset makes an instant, a date and time without one is a wall clock. The basic form reads too, and a bracketed offset stands in for the one beside it — but a zone name keeps the minute, so [-12:12:59] is refused.

02

Next firings

03

Zones at one instant

Six cities, one instant. Kathmandu is +05:45, Lord Howe and Chatham run their daylight saving half an hour at a time.

04

The hour that is not there

Whether a clock reads once, twice or never is a fact about the zone; which of the two to take is the caller's. A clock that never happens is read as the instant just after the gap, which is why 02:30 in March comes back as 03:30.

Under the hood

How next finds the answer.

next starts one second after the given moment, floors to a whole second, then walks forward one second at a time until the six bit sets all agree. The search is bounded at four years — past any leap-year cycle a real schedule turns on — so an expression naming a day that does not exist returns None instead of looping.

* * * * * * │ │ │ │ │ └── day of week 0-7, or SUN-SAT │ │ │ │ └───── month 1-12, or JAN-DEC │ │ │ └──────── day of month 1-31 │ │ └─────────── hour 0-23 │ └────────────── minute 0-59 └───────────────── second 0-59, six fields only

Both 0 and 7 are Sunday. ? reads as *, which is how a day field that is not in use is usually written.

five fields, no seconds
0 9 * * MON-FRI     every weekday at 09:00
*/15 9-17 * * MON-FRI   quarter hours, 09:00-17:45
0 0 1 * *           the first of the month
0 0 29 2 *          the leap day, when it exists
Day fields are or-ed. When both day-of-month and day-of-week are restricted, a moment matches if either does. With one of them * they are and-ed, so 0 0 13 * * is only the thirteenth.