Calendars
zdate ships 18 calendar engines with conversion and arithmetic: solar, lunar, and lunisolar.
iso8601, gregory, buddhist, japanese, roc, indian, persian, coptic, ethiopic, ethioaa, hebrew, islamic-civil, islamic-tbla, islamic, islamic-rgsa, islamic-umalqura, chinese, dangi
A calendar is a view concern. with() returns a new instance carrying the same epoch with different view options:
const d = zdate('2024-01-15T12:00:00Z')
const h = d.with({calendar: 'hebrew'})
h.utc.year // 5784
h.epoch === d.epoch // true — same instant, different projection
d.with({calendar: 'japanese'}).utc.era // 'Reiwa'Calendar-Aware Arithmetic
by() and to() operate in the view's calendar. Adding a month in the Hebrew calendar respects Hebrew month lengths and leap months; moving to 'start of year' in the Persian calendar lands on Nowruz.
const h = zdate({year: 5784, month: 5, day: 5, calendar: 'hebrew'}, {calendar: 'source'})
h.by({months: 1}) // Hebrew month arithmetic
h.to('start of year') // Hebrew new yearConstruction from Calendar Fields
The calendar property inside the fields names the calendar the fields are expressed in. Without it, fields are ISO 8601:
zdate({year: 1445, month: 7, day: 4, calendar: 'islamic-umalqura'})
zdate({year: 2024, month: 1, day: 15}) // iso8601The fields' calendar and the view's calendar are separate concerns. The fields' calendar resolves the instant; the view option controls how the result is read. Pass {calendar: 'source'} as the view options to adopt the fields' calendar for the views.
The era field is required for gregory, japanese, roc, ethiopic, and coptic; it is ignored for all other calendars.
RFC 9557 Suffix Calendars
A [u-ca=...] suffix is captured on parsedSuffix and adopted as the view calendar only when requested with 'source' — the same rule as a suffix zone:
const d = zdate('2024-01-15T12:00:00Z[u-ca=hebrew]', {calendar: 'source'})
d.utc.year // 5784
d.parsedSuffix?.calendar // 'hebrew', with or without 'source'An unknown non-critical suffix calendar is ignored; an unknown critical one ([!u-ca=...]) throws.
Engine Notes
The engines implement their own conversion and arithmetic. Intl participates where it is the right boundary — reference data for observational calendars — with zdate's math and caching around it.
Every engine is verified by round-trip: Gregorian/ISO date to calendar date and back to Gregorian/ISO, sampled every 3 days across the tested range. See Round-Trip Verification.
| Calendar | Supported range | Notes |
|---|---|---|
| All calendars | -267,000 to +267,000 | Hard limit; zdate rejects dates outside it |
japanese | from 645 CE | The calendar starts at Taika 1; zdate rejects earlier dates because pre-645 Taika years are semantically questionable |
chinese / dangi | -30,000 to +65,000 | ICU errors internally for years outside this range |
For the Japanese start boundary: Gregorian 0645-01-01 is still year 0 in the Japanese calendar (offset by Julian-Gregorian drift). The Japanese range begins at Gregorian 0645-01-04, which is Taika 0001-01-01.
