Calendar Systems

Timestamp treats Gregorian dates as the default public contract. Calendar-aware helpers accept a CalendarSystem argument and default to gregorianCalendar, so existing calls keep their Gregorian behavior while adapter-based code can use native calendar fields.

The calendar-system work starts underneath that contract. Core exposes a CalendarSystem adapter shape and a built-in gregorianCalendar adapter so future calendar packages can plug into the same date math model instead of creating separate, incompatible helper APIs. Adapter-produced timestamps can use the optional calendarId field, but the current Gregorian core helpers leave it unset so existing object output remains stable.

Keep @timestamp-js/core small and predictable:

  • Core owns shared types, immutable Timestamp objects, comparison/range primitives, time helpers, and the default Gregorian adapter.
  • Optional calendar packages own calendar-specific math and parsing. Timestamp currently publishes @timestamp-js/calendar-islamic, @timestamp-js/calendar-saka, @timestamp-js/calendar-hebrew, and @timestamp-js/calendar-persian; future adapters can add other systems without changing the core package.
  • The Gregorian adapter remains available from core first. A separate @timestamp-js/calendar-gregorian package can be added later if external adapter packages need a reusable reference implementation.

This keeps existing users on one package while making advanced calendar support opt-in.

Current adapters

Timestamp currently ships the default Gregorian adapter from @timestamp-js/core and optional adapter packages for Islamic civil, Indian National/Saka, Hebrew, and Persian dates. Optional adapters use the same CalendarSystem contract, which keeps the conversion surface small while letting each package own its calendar rules.

  • Islamic Civil (Hijri) documents the deterministic tabular Hijri calendar, including Arabic labels, RTL presentation, and native week/month ranges.
  • Saka documents the Indian National Calendar adapter, including locale-aware labels and native week/month ranges.
  • Hebrew documents the arithmetic Hebrew calendar adapter, including civil/CLDR month numbering, RTL presentation, and native week/month ranges.
  • Persian documents the Persian/Jalali calendar adapter, including civil month numbering, RTL presentation, and native week/month ranges.

Additional calendar pages should be added under this section as new adapters prove their behavior against real calendar, picker, scheduler, and data workflow usage.

If your application needs a calendar Timestamp does not publish yet, start with Create a Calendar Adapter. Custom adapters use the same CalendarSystem contract as the built-in Gregorian adapter and optional adapter packages.

Adapter contract

A calendar adapter needs to answer questions that are calendar-specific:

import type { CalendarSystem } from '@timestamp-js/core'

export const const myCalendar: CalendarSystemmyCalendar: CalendarSystem = {
  CalendarSystem.id: CalendarId
Package-facing calendar id.
id
: 'my-calendar',
CalendarSystem.label: string
Human-readable calendar name.
label
: 'My Calendar',
CalendarSystem.defaultLocale?: string | undefined
Recommended BCP 47 locale for presentation when the caller does not provide one.
defaultLocale
: 'en-US',
CalendarSystem.defaultDirection?: CalendarDirection | undefined
Recommended text direction for presentation when the caller does not provide one.
defaultDirection
: 'ltr',
CalendarSystem.defaultWeekdays?: readonly number[] | undefined
Recommended visible weekday order when the caller does not provide one. Weekdays use JavaScript numbering, where Sunday is `0` and Saturday is `6`.
defaultWeekdays
: [0, 1, 2, 3, 4, 5, 6],
CalendarSystem.monthsInYear(year: number): number
Number of months in a calendar year.
monthsInYear
(year: numberyear) {
return 12 }, CalendarSystem.isLeapYear(year: number): boolean
True when the calendar year has a leap day or leap month.
isLeapYear
(year: numberyear) {
return false }, CalendarSystem.daysInMonth(year: number, month: number): number
Number of days in the specified calendar month.
daysInMonth
(year: numberyear, month: numbermonth) {
return 30 }, CalendarSystem.toEpochDay(date: CalendarDateParts): number
Converts a calendar date into a stable serial day. For Gregorian this is the number of UTC days since 1970-01-01. Other calendar adapters should return the serial day for the equivalent civil instant so comparisons and ranges can stay calendar-agnostic.
toEpochDay
(date: CalendarDatePartsdate) {
// Convert calendar fields to a stable serial day. return 0 }, CalendarSystem.fromEpochDay(epochDay: number): CalendarDateParts
Converts a stable serial day into calendar date fields.
fromEpochDay
(epochDay: numberepochDay) {
// Convert the stable serial day back to calendar fields. return { CalendarDateParts.year: number
Calendar year.
year
: 1, CalendarDateParts.month: number
Calendar month number. The first month is `1`.
month
: 1, CalendarDateParts.day: number
Day of the month. The first day is `1`.
day
: 1 }
}, CalendarSystem.addDays(date: CalendarDateParts, amount: number): CalendarDateParts
Moves a calendar date by a whole number of days.
addDays
(date: CalendarDatePartsdate, amount: numberamount) {
return this.CalendarSystem.fromEpochDay(epochDay: number): CalendarDateParts
Converts a stable serial day into calendar date fields.
fromEpochDay
(this.CalendarSystem.toEpochDay(date: CalendarDateParts): number
Converts a calendar date into a stable serial day. For Gregorian this is the number of UTC days since 1970-01-01. Other calendar adapters should return the serial day for the equivalent civil instant so comparisons and ranges can stay calendar-agnostic.
toEpochDay
(date: CalendarDatePartsdate) + amount: numberamount)
}, CalendarSystem.nextDay(date: CalendarDateParts): CalendarDateParts
Returns the next calendar date.
nextDay
(date: CalendarDatePartsdate) {
return this.CalendarSystem.addDays(date: CalendarDateParts, amount: number): CalendarDateParts
Moves a calendar date by a whole number of days.
addDays
(date: CalendarDatePartsdate, 1)
}, CalendarSystem.prevDay(date: CalendarDateParts): CalendarDateParts
Returns the previous calendar date.
prevDay
(date: CalendarDatePartsdate) {
return this.CalendarSystem.addDays(date: CalendarDateParts, amount: number): CalendarDateParts
Moves a calendar date by a whole number of days.
addDays
(date: CalendarDatePartsdate, -1)
}, CalendarSystem.getDayOfYear(date: CalendarDateParts): number
Returns day-of-year for a calendar date.
getDayOfYear
(date: CalendarDatePartsdate) {
return 1 }, CalendarSystem.getWeekday(date: CalendarDateParts): number
Returns weekday where Sunday is `0` and Saturday is `6`.
getWeekday
(date: CalendarDatePartsdate) {
return 0 }, } myCalendar
const myCalendar: CalendarSystem

The important part is epochDay. Calendar year/month/day fields are not directly comparable across calendar systems. An adapter maps its fields to a stable serial day so ranges, min/max, disabled dates, selected dates, and list generation can stay calendar-agnostic internally while public component APIs remain adapter-native.

Presentation fields such as defaultLocale, defaultDirection, and defaultWeekdays are optional recommendations. Components can use them when the app does not pass explicit display props, but callers can still override them for another language, direction, or work-week layout.

Use getCalendarLocale(), getCalendarDirection(), isCalendarRTL(), and getCalendarWeekdays() when component or application code needs to read those defaults without reaching into adapter internals. Each helper falls back to Gregorian defaults if an adapter omits a presentation field.

Calendar-aware core helpers

Core keeps the original helper names stable and makes calendar math adapter-capable where it makes sense. Helpers such as today(), parseDate(), nextDay(), daysInMonth(), getStartOfWeek(), createDayList(), updateFormatted(), updateRelative(), and addToDate() default to Gregorian but accept a CalendarSystem when the input/output date fields should be native to another calendar.

The explicitly named calendar helpers remain useful for component and adapter work because their purpose is unambiguous and they return timestamp-shaped objects tagged with the adapter id:

import {
  function createCalendarDayList(start: Timestamp, end: Timestamp, now: Timestamp, calendar?: CalendarSystem, options?: CalendarDayListOptions): Timestamp[]
Creates an inclusive list of calendar adapter days between start and end.
@paramstart First day in the list.@paramend Last day boundary for the list.@paramnow Timestamp used to calculate relative flags.@paramcalendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.@paramoptions Optional weekday, disabled, and size filters.@returnsTimestamp days for the adapter calendar.@categorycalendar
createCalendarDayList
,
function createCalendarMonthView(timestamp: Timestamp, now: Timestamp, calendar?: CalendarSystem, options?: CalendarMonthViewOptions): CalendarMonthView
Creates native calendar month view state for component rendering. The returned `days` use adapter-native `YYYY-MM-DD` values, while each state's identity also includes Gregorian interop metadata.
@paramtimestamp Reference timestamp in the adapter calendar.@paramnow Timestamp used to calculate relative flags.@paramcalendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.@paramoptions Calendar-aware disabled, selection, weekday, and size options.@returnsCalendar month view state.@categorycalendar
createCalendarMonthView
,
function formatCalendarDateLabel(timestamp: Timestamp, calendar?: CalendarSystem, options?: Intl.DateTimeFormatOptions, locale?: string): string
Formats a calendar timestamp date with Intl using adapter defaults. The timestamp's adapter date fields are converted through the calendar before Intl receives the equivalent Gregorian Date. Use this for native calendar labels in UI examples and application code.
@paramtimestamp Calendar timestamp to format.@paramcalendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar presentation.@paramoptions Intl date formatting options. Defaults to `{ year: 'numeric', month: 'long', day: 'numeric' }`.@paramlocale Locale to use for formatting. Defaults to the calendar adapter locale.@returnsLocalized calendar date label, or an empty string when formatting fails.@categorycalendar
formatCalendarDateLabel
,
function getCalendarDateIdentity(timestamp: Timestamp, calendar?: CalendarSystem): CalendarDateIdentity
Creates stable native and Gregorian identities for a calendar timestamp. Use this when component APIs need to expose adapter-native values while also preserving a canonical Gregorian key for storage, comparisons, or interop with existing data.
@paramtimestamp Timestamp object to identify.@paramcalendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.@returnsCalendar-native date, Gregorian interop date, and shared epoch day.@categorycalendar
getCalendarDateIdentity
,
function getCalendarEndOfMonth(timestamp: Timestamp, calendar?: CalendarSystem): Timestamp
Returns the end of the calendar month for a timestamp.
@paramtimestamp Base timestamp.@paramcalendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.@returnsLast day of the adapter month.@categorycalendar
getCalendarEndOfMonth
,
function getCalendarMonthName(calendar: CalendarSystem | undefined, month: number, type?: string, locale?: string, year?: number): string
Formats one month number using calendar adapter defaults. Month numbers are one-based for calendar adapters.
@paramcalendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar presentation.@parammonth Calendar month number, where the first month is `1`.@paramtype Format type: `narrow`, `short`, or `long`.@paramlocale Locale to use for formatting. Defaults to the calendar adapter locale.@paramyear Calendar year to sample. Defaults to `1`.@returnsLocalized month name.@categorycalendar
getCalendarMonthName
,
function getCalendarWeekdayNames(calendar?: CalendarSystem, type?: string, locale?: string, weekdays?: readonly number[]): string[]
Retrieves localized weekday names using calendar adapter defaults.
@paramcalendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar presentation.@paramtype Format type: `narrow`, `short`, or `long`.@paramlocale Locale to use for formatting. Defaults to the calendar adapter locale.@paramweekdays Weekday order to format. Defaults to the calendar adapter weekday order.@returnsLocalized weekday names in the requested weekday order.@categorycalendar
getCalendarWeekdayNames
,
function getCalendarSelectionState(timestamp: Timestamp, options?: CalendarSelectionOptions, calendar?: CalendarSystem): CalendarSelectionState
Resolves selected-date and selected-range state for a calendar timestamp. The default Gregorian calendar preserves existing Timestamp behavior. When an alternate calendar is supplied, selected date strings are parsed as native adapter dates.
@paramtimestamp Timestamp to inspect.@paramoptions Selected dates and selected start/end dates.@paramcalendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.@returnsSelected-date state for the timestamp.@categorycalendar
getCalendarSelectionState
,
function parseCalendarTimestamp(input: string, calendar?: CalendarSystem, now?: Timestamp | null): Timestamp | null
Parses a date or date-time string as calendar adapter fields. Unlike parseTimestamp(), this helper validates the date against the supplied calendar and derives weekday/day-of-year values through the adapter.
@paraminput Date or date-time string.@paramcalendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.@paramnow Optional comparison timestamp from the same calendar system.@returnsCalendar timestamp, or `null` when the input cannot be parsed or validated.@categorycalendar
parseCalendarTimestamp
,
function updateCalendarDisabled(timestamp: Timestamp, disabledBefore?: string, disabledAfter?: string, disabledWeekdays?: number[], disabledDays?: DisabledDays, calendar?: CalendarSystem): Timestamp
Updates a timestamp with disabled state using calendar-native date strings. The default Gregorian calendar preserves existing Timestamp behavior. When an alternate calendar is supplied, `disabledBefore`, `disabledAfter`, and `disabledDays` are parsed as native dates for that adapter.
@paramtimestamp Timestamp to transform.@paramdisabledBefore Disable days on or before this adapter date.@paramdisabledAfter Disable days on or after this adapter date.@paramdisabledWeekdays Weekday numbers to mark disabled.@paramdisabledDays Specific adapter dates or date ranges to mark disabled.@paramcalendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.@returnsNew timestamp with disabled metadata applied.@categorycalendar
updateCalendarDisabled
,
} from '@timestamp-js/core' import { const islamicCivilCalendar: CalendarSystem
Deterministic tabular Islamic civil calendar. This adapter intentionally models the arithmetic/civil Hijri calendar. It does not model observational calendars or Umm al-Qura adjustments.
islamicCivilCalendar
} from '@timestamp-js/calendar-islamic'
const const visible: Timestampvisible = function parseCalendarTimestamp(input: string, calendar?: CalendarSystem, now?: Timestamp | null): Timestamp | null
Parses a date or date-time string as calendar adapter fields. Unlike parseTimestamp(), this helper validates the date against the supplied calendar and derives weekday/day-of-year values through the adapter.
@paraminput Date or date-time string.@paramcalendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.@paramnow Optional comparison timestamp from the same calendar system.@returnsCalendar timestamp, or `null` when the input cannot be parsed or validated.@categorycalendar
parseCalendarTimestamp
('1445-09-01', const islamicCivilCalendar: CalendarSystem
Deterministic tabular Islamic civil calendar. This adapter intentionally models the arithmetic/civil Hijri calendar. It does not model observational calendars or Umm al-Qura adjustments.
islamicCivilCalendar
)!
const const start: Timestampstart = const visible: Timestampvisible const const end: Timestampend = function getCalendarEndOfMonth(timestamp: Timestamp, calendar?: CalendarSystem): Timestamp
Returns the end of the calendar month for a timestamp.
@paramtimestamp Base timestamp.@paramcalendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.@returnsLast day of the adapter month.@categorycalendar
getCalendarEndOfMonth
(const visible: Timestampvisible, const islamicCivilCalendar: CalendarSystem
Deterministic tabular Islamic civil calendar. This adapter intentionally models the arithmetic/civil Hijri calendar. It does not model observational calendars or Umm al-Qura adjustments.
islamicCivilCalendar
)
const const days: Timestamp[]days = function createCalendarDayList(start: Timestamp, end: Timestamp, now: Timestamp, calendar?: CalendarSystem, options?: CalendarDayListOptions): Timestamp[]
Creates an inclusive list of calendar adapter days between start and end.
@paramstart First day in the list.@paramend Last day boundary for the list.@paramnow Timestamp used to calculate relative flags.@paramcalendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.@paramoptions Optional weekday, disabled, and size filters.@returnsTimestamp days for the adapter calendar.@categorycalendar
createCalendarDayList
(const start: Timestampstart, const end: Timestampend, const visible: Timestampvisible, const islamicCivilCalendar: CalendarSystem
Deterministic tabular Islamic civil calendar. This adapter intentionally models the arithmetic/civil Hijri calendar. It does not model observational calendars or Umm al-Qura adjustments.
islamicCivilCalendar
)
const const monthLabel: stringmonthLabel = function getCalendarMonthName(calendar: CalendarSystem | undefined, month: number, type?: string, locale?: string, year?: number): string
Formats one month number using calendar adapter defaults. Month numbers are one-based for calendar adapters.
@paramcalendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar presentation.@parammonth Calendar month number, where the first month is `1`.@paramtype Format type: `narrow`, `short`, or `long`.@paramlocale Locale to use for formatting. Defaults to the calendar adapter locale.@paramyear Calendar year to sample. Defaults to `1`.@returnsLocalized month name.@categorycalendar
getCalendarMonthName
(
const islamicCivilCalendar: CalendarSystem
Deterministic tabular Islamic civil calendar. This adapter intentionally models the arithmetic/civil Hijri calendar. It does not model observational calendars or Umm al-Qura adjustments.
islamicCivilCalendar
,
const visible: Timestampvisible.Timestamp.month: number
Calendar month number, where the first month is `1`. Core parser helpers use Gregorian month numbers.
month
,
'long', 'en-US', const visible: Timestampvisible.Timestamp.year: number
Calendar year. Core parser helpers use Gregorian years.
year
,
) const const weekdayLabels: string[]weekdayLabels = function getCalendarWeekdayNames(calendar?: CalendarSystem, type?: string, locale?: string, weekdays?: readonly number[]): string[]
Retrieves localized weekday names using calendar adapter defaults.
@paramcalendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar presentation.@paramtype Format type: `narrow`, `short`, or `long`.@paramlocale Locale to use for formatting. Defaults to the calendar adapter locale.@paramweekdays Weekday order to format. Defaults to the calendar adapter weekday order.@returnsLocalized weekday names in the requested weekday order.@categorycalendar
getCalendarWeekdayNames
(const islamicCivilCalendar: CalendarSystem
Deterministic tabular Islamic civil calendar. This adapter intentionally models the arithmetic/civil Hijri calendar. It does not model observational calendars or Umm al-Qura adjustments.
islamicCivilCalendar
, 'short', 'en-US')
const const visibleLabel: stringvisibleLabel = function formatCalendarDateLabel(timestamp: Timestamp, calendar?: CalendarSystem, options?: Intl.DateTimeFormatOptions, locale?: string): string
Formats a calendar timestamp date with Intl using adapter defaults. The timestamp's adapter date fields are converted through the calendar before Intl receives the equivalent Gregorian Date. Use this for native calendar labels in UI examples and application code.
@paramtimestamp Calendar timestamp to format.@paramcalendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar presentation.@paramoptions Intl date formatting options. Defaults to `{ year: 'numeric', month: 'long', day: 'numeric' }`.@paramlocale Locale to use for formatting. Defaults to the calendar adapter locale.@returnsLocalized calendar date label, or an empty string when formatting fails.@categorycalendar
formatCalendarDateLabel
(
const visible: Timestampvisible, const islamicCivilCalendar: CalendarSystem
Deterministic tabular Islamic civil calendar. This adapter intentionally models the arithmetic/civil Hijri calendar. It does not model observational calendars or Umm al-Qura adjustments.
islamicCivilCalendar
,
{ Intl.DateTimeFormatOptions.month?: "long" | "short" | "numeric" | "2-digit" | "narrow" | undefinedmonth: 'long', Intl.DateTimeFormatOptions.day?: "numeric" | "2-digit" | undefinedday: 'numeric', Intl.DateTimeFormatOptions.year?: "numeric" | "2-digit" | undefinedyear: 'numeric', }, 'en-US', ) const const identity: CalendarDateIdentityidentity = function getCalendarDateIdentity(timestamp: Timestamp, calendar?: CalendarSystem): CalendarDateIdentity
Creates stable native and Gregorian identities for a calendar timestamp. Use this when component APIs need to expose adapter-native values while also preserving a canonical Gregorian key for storage, comparisons, or interop with existing data.
@paramtimestamp Timestamp object to identify.@paramcalendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.@returnsCalendar-native date, Gregorian interop date, and shared epoch day.@categorycalendar
getCalendarDateIdentity
(const days: Timestamp[]days[0], const islamicCivilCalendar: CalendarSystem
Deterministic tabular Islamic civil calendar. This adapter intentionally models the arithmetic/civil Hijri calendar. It does not model observational calendars or Umm al-Qura adjustments.
islamicCivilCalendar
)
const const disabled: Timestampdisabled = function updateCalendarDisabled(timestamp: Timestamp, disabledBefore?: string, disabledAfter?: string, disabledWeekdays?: number[], disabledDays?: DisabledDays, calendar?: CalendarSystem): Timestamp
Updates a timestamp with disabled state using calendar-native date strings. The default Gregorian calendar preserves existing Timestamp behavior. When an alternate calendar is supplied, `disabledBefore`, `disabledAfter`, and `disabledDays` are parsed as native dates for that adapter.
@paramtimestamp Timestamp to transform.@paramdisabledBefore Disable days on or before this adapter date.@paramdisabledAfter Disable days on or after this adapter date.@paramdisabledWeekdays Weekday numbers to mark disabled.@paramdisabledDays Specific adapter dates or date ranges to mark disabled.@paramcalendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.@returnsNew timestamp with disabled metadata applied.@categorycalendar
updateCalendarDisabled
(
const days: Timestamp[]days[0], var undefinedundefined, var undefinedundefined, [], ['1445-09-01'], const islamicCivilCalendar: CalendarSystem
Deterministic tabular Islamic civil calendar. This adapter intentionally models the arithmetic/civil Hijri calendar. It does not model observational calendars or Umm al-Qura adjustments.
islamicCivilCalendar
,
) const const selection: CalendarSelectionStateselection = function getCalendarSelectionState(timestamp: Timestamp, options?: CalendarSelectionOptions, calendar?: CalendarSystem): CalendarSelectionState
Resolves selected-date and selected-range state for a calendar timestamp. The default Gregorian calendar preserves existing Timestamp behavior. When an alternate calendar is supplied, selected date strings are parsed as native adapter dates.
@paramtimestamp Timestamp to inspect.@paramoptions Selected dates and selected start/end dates.@paramcalendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.@returnsSelected-date state for the timestamp.@categorycalendar
getCalendarSelectionState
(
const days: Timestamp[]days[0], { CalendarSelectionOptions.selectedStartEndDates?: string[] | undefined
Two adapter-native date strings marking an inclusive selected range.
selectedStartEndDates
: ['1445-09-01', '1445-09-05'] },
const islamicCivilCalendar: CalendarSystem
Deterministic tabular Islamic civil calendar. This adapter intentionally models the arithmetic/civil Hijri calendar. It does not model observational calendars or Umm al-Qura adjustments.
islamicCivilCalendar
,
) const const monthView: CalendarMonthViewmonthView = function createCalendarMonthView(timestamp: Timestamp, now: Timestamp, calendar?: CalendarSystem, options?: CalendarMonthViewOptions): CalendarMonthView
Creates native calendar month view state for component rendering. The returned `days` use adapter-native `YYYY-MM-DD` values, while each state's identity also includes Gregorian interop metadata.
@paramtimestamp Reference timestamp in the adapter calendar.@paramnow Timestamp used to calculate relative flags.@paramcalendar Calendar system to use. Defaults to Gregorian; pass an adapter such as islamicCivilCalendar for native calendar fields.@paramoptions Calendar-aware disabled, selection, weekday, and size options.@returnsCalendar month view state.@categorycalendar
createCalendarMonthView
(const visible: Timestampvisible, const visible: Timestampvisible, const islamicCivilCalendar: CalendarSystem
Deterministic tabular Islamic civil calendar. This adapter intentionally models the arithmetic/civil Hijri calendar. It does not model observational calendars or Umm al-Qura adjustments.
islamicCivilCalendar
, {
CalendarSelectionOptions.selectedDates?: CalendarDateCollection | undefined
Adapter-native date strings to mark as selected.
selectedDates
: ['1445-09-03'],
CalendarDisabledOptions.disabledDays?: DisabledDays | undefined
Specific dates or date ranges to mark disabled.
disabledDays
: ['1445-09-04'],
}) const days: Timestamp[]days[0].Timestamp.calendarId?: CalendarId | undefined
Optional calendar-system identifier for adapter-produced timestamps. Core Gregorian helpers omit this field for backwards compatibility.
calendarId
// 'islamic-civil'
const days: Timestamp[]days[0].Timestamp.date: string
Date string in `YYYY-MM-DD` form when the timestamp has a day.
date
// '1445-09-01'
const monthLabel: stringmonthLabel // 'Ramadan' const weekdayLabels: string[]weekdayLabels // ['Sat', 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri'] const visibleLabel: stringvisibleLabel // 'Ramadan 1, 1445 AH' const identity: CalendarDateIdentityidentity.CalendarDateIdentity.nativeDate: string
Native calendar date string in `YYYY-MM-DD` form.
nativeDate
// '1445-09-01'
const identity: CalendarDateIdentityidentity.CalendarDateIdentity.gregorianDate: string
Canonical Gregorian date string for the same serial day.
gregorianDate
// '2024-03-11'
const identity: CalendarDateIdentityidentity.CalendarDateIdentity.epochDay: number
Stable serial day shared across calendar systems.
epochDay
// stable cross-calendar sort/range key
const disabled: Timestampdisabled.Timestamp.disabled?: boolean | undefined
True when this timestamp represents a disabled date.
disabled
// true
const selection: CalendarSelectionStateselection.CalendarSelectionState.rangeFirst: boolean
True when the date is the selected range start.
rangeFirst
// true
const monthView: CalendarMonthViewmonthView.CalendarMonthView.days: CalendarDateState[]
Rendered adapter-native day states.
days
[0].CalendarDateState.timestamp: Timestamp
Adapter-native timestamp for the rendered date.
timestamp
.Timestamp.date: string
Date string in `YYYY-MM-DD` form when the timestamp has a day.
date
// adapter-native YYYY-MM-DD
const monthView: CalendarMonthViewmonthView.CalendarMonthView.days: CalendarDateState[]
Rendered adapter-native day states.
days
[0].CalendarDateState.identity: CalendarDateIdentity
Stable native/Gregorian identity for the rendered date.
identity
.CalendarDateIdentity.gregorianDate: string
Canonical Gregorian date string for the same serial day.
gregorianDate
// Gregorian interop metadata

These helpers are the bridge for calendar-style views: adapters own calendar math, and core turns adapter dates into immutable Timestamp objects with weekday, doy, past, current, future, disabled state, selection/range state, outside-month state, and identity metadata. For component or application APIs that need to feel adapter-native, expose the native fields while keeping gregorianDate and epochDay available as deterministic interop keys.

Gregorian interop metadata

Adapter-native dates should be the main contract when a component receives a CalendarSystem. For example, a Saka calendar view should accept, emit, select, and disable Saka YYYY-MM-DD strings so application code does not have to translate every interaction.

Timestamp still keeps Gregorian interop metadata available because real applications often have to cross calendar boundaries:

  • Existing apps may already store records keyed by Gregorian ISO dates.
  • APIs, databases, exports, and analytics pipelines often expect Gregorian dates even when the UI is native to another calendar.
  • Cross-calendar comparisons need a neutral serial key. Use epochDay for that job rather than a Gregorian display string.
  • Debugging and migration are easier when you can see which civil/Gregorian day an adapter-native date maps to.
  • Integrations can adopt native calendar UI incrementally without rewriting every storage or reporting boundary at the same time.

Treat gregorianDate as interop metadata and epochDay as the durable comparison key. User-facing calendar state should stay native to the active adapter.

When a component accepts a calendar adapter, YYYY-MM-DD values at that component boundary should be treated as native to that adapter. For example, selected-dates, disabled-days, and model-value should all use Hijri strings when the Islamic civil adapter is active. Timestamp helpers keep comparisons stable by converting those native strings to epochDay internally.

First-class support vs. display-only support

Locale labels and calendar math are different problems. Intl.DateTimeFormat can format labels with calendar options in many runtimes, but display-only formatting is not enough for calendar views. A real calendar adapter must control month length, leap rules, navigation, weekday calculation, and range comparisons.

That means Islamic/Hijri, Hebrew, Indian National/Saka, Persian, and other non-Gregorian calendars should be treated as first-class adapter work, not only as translated Gregorian dates.

Temporal

Temporal is the right ecosystem direction to watch. Temporal.PlainDate carries calendar-system metadata, and Temporal is designed to replace the older JavaScript Date model. Timestamp is keeping its adapter contract small for now because Temporal is still not available in every target browser, and calendar-style views need deterministic adapter rules for range generation, list generation, and package-level tree shaking.

The current adapter shape should stay easy to bridge later: adapters already convert their year/month/day fields through a stable serial day, which is the same boundary adapter-aware consumers need when different calendar systems eventually share the same view code.

Integration status

The top-level helpers default to Gregorian for compatibility. When a CalendarSystem can be supplied, new component-facing code should pass it through consistently so parsing, navigation, range generation, disabled/selected state, relative flags, and formatted metadata all use the same calendar.

Use parseCalendarTimestamp() for adapter-native YYYY-MM-DD strings. Use helpers such as nextDay(timestamp, calendar), createDayList(..., calendar), and updateRelative(timestamp, now, time, calendar) when working with timestamp objects that already belong to a calendar. Use the *Calendar* helper names when that makes the call site clearer.

Islamic civil, Saka, Hebrew, and Persian are the current proving adapters. Future adapters with leap months or non-linear month naming will be the next design pressure point because those calendars need an explicit model representation before Timestamp can expose unambiguous native YYYY-MM-DD strings.