Context
OS scheduling-calendar, geography and workforce, Commerce (delivery promise, Hijri promotions), Muslin (seasons), Beautilon (recurring appointments, processing gaps), Juristra (deadlines, court calendars) and Academorix (recurring sessions, age cut-offs) all need the same date mechanism, and nothing is on disk. Each country’s working week, public holidays, Hijri adjustments and court recesses differ and change by announcement, and moon-sighted holidays are not known in advance. 0363 forbids any of that in code. The same arithmetic must run offline on a till and on the server. Alternatives weighed: a third-party RRULE and time-zone stack (rrule, luxon), and a Hijri table shipped in the
package; both add dependencies or data the runtime’s ICU already provides.
Decision
- Package.
@stackra/calendarinpackages/foundation/calendar,tier:lib, entry.only, depending on@stackra/contractsandzod. It is pure mechanism with no persistence, so it sits infoundation, notdata. - One storage form. Dates are stored and passed as Gregorian
YYYY-MM-DD; instants as ISO 8601 with an offset. Hijri is computed with the runtime’sislamic-umalquracalendar (hijriOf,gregorianOf). A runtime without it throws; the package never falls back to the arithmetic Hijri calendar. - Calendar data, not code. A
BusinessCalendarholds a time zone, a working week (weekdays with hours; a span whose end is not after its start runs past midnight), holiday rules anduncertainDays. A holiday rule is a dated span, a yearly Gregorian date or a yearly Hijri date withsighted,sinceanduntil. Market packs supply the base; tenants, branches and courts add closures and recesses as more rules. A court working week is the same data.BusinessCalendar$checks the shape; the package ships no values. - Uncertain, never guessed. A sighted Hijri occurrence is
uncertainuntil a dated rule with the same key in that Hijri year confirms or moves it. Business-day results list every uncertain day crossed. Whether an uncertain day counts as working or closed is the calendar’suncertainDaysvalue. - Time zones and working hours come from the runtime’s IANA data through
Intl:instantOf,localDateOf,openIntervalsandaddWorkingMinutes. Local wall times survive clock changes. - Recurrence is RFC 5545 RRULE with FREQ (daily to yearly), INTERVAL, COUNT, UNTIL, BYDAY (with month positions), BYMONTHDAY, BYMONTH and WKST, expanded in a time zone through a required window. Other parts are refused, not ignored. Holidays of a given calendar are skipped; excepted and skipped dates still count toward COUNT.
- Slots are start times where every segment that holds the resource lies in open time and overlaps no busy block; processing-gap segments may overlap anything.
- Age on a date is whole years; the 29 February rule is a parameter from the pack (
LeapBirthday). - Not here. Legal counting rules (trigger day, roll-forward, extensions) stay in the product’s rules or deadline
engine; display formatting stays in
@stackra/i18n; calendar sync stays with connectors; the market-pack loader stays an open question of 0363.
Consequences
- A new market’s weekend or holidays is a pack edit; a late Hijri announcement is one dated rule.
- Deadline and delivery promises can warn on uncertainty instead of silently moving a date.
- Hermes and other engines must ship full ICU for Hijri and time zones; a missing calendar fails loudly.
- Callers merge pack and tenant rules themselves until the pack loader exists.
- RRULE parts outside the list need an amendment of this ADR before use.
Enforcement
planned — the package’s tests (packages/foundation/calendar/src/**/__tests__/) fix the behaviour and use made-up
fixtures only; the lint rule of 0363 will flag country or holiday literals in the source. Nothing checks it in CI
yet.
Supersedes and sources
Supersedes: none. Sources:notes/handover/stackra-package-needs.md (@stackra/calendar row);
notes/handover/owner-questionnaire-2026-10-25.md #18; notes/handover/config-model.md (Calendar part of a pack);
notes/handover/answers-as-config.md (CAP-calendar; OS-179, OS-245, COM-150, COM-178, COM-342, PUT-46, PUT-67,
JUR-115, JUR-121, JUR-284, ACA-82, ACA-87); notes/handover/product-capability-map-2026-10-25.md.