Calendar

:= [Gregorian, Julian]

Calendar profiles and their related dates, quantities and selections. Date retains calendar identity; Delta describes calendar components; Value retains supplied resolution. Arithmetic requires an explicit policy. Gregorian and Julian profiles are proleptic; no historical reform is inferred.

is_eq : Calendar, Calendar -> Bool

Whether two calendar profiles identify the same calendar. This does not compare dates or their extents.

to_hash : Calendar, Hasher -> Hasher

Hash calendar identity consistently with equality for dictionary/set keys.

to_inspect : Calendar -> Str

Return the calendar name in a concise diagnostic description.

from_name : Str -> Try(Calendar, [UnsupportedCalendar(Str)])

Select a supported profile from the exact name gregorian or julian. Other names return UnsupportedCalendar with the supplied name.

to_name : Calendar -> Str

Return the profile name: gregorian or julian.

Arithmetic

Calendar.Arithmetic :: # (opaque)

Gregorian date arithmetic with explicit invalid-date policy. Components apply in year/month/day order; this is not recurrence expansion. For January 31 plus one month, Clamp chooses February's last day; Reject returns InvalidDestination, and Carry moves excess days into March. Work is constant, without zone resolution. Provider limits return OutOfRange.

shift_day : GregorianDate, Delta, Policy -> Try(GregorianDate, [OutOfRange, InvalidDestination(Fields)])

Apply years, then months, then civil days to a Gregorian date. Choose Reject, Clamp or Carry for nonexistent intermediate destinations. Return InvalidDestination or OutOfRange rather than silently choosing a policy. Clamping is not invertible and must not be used to step RFC recurrence rules.

Policy : [Reject, Clamp, Carry]

Handling for nonexistent intermediate dates: Reject fails, Clamp uses the destination month's last day, and Carry advances excess days past it.

Date

Calendar.Date :: # (opaque)

A validated day description retaining its calendar. Resolution is one civil day.

from_gregorian : GregorianDate -> Date

Preserve an already validated date and its calendar without revalidation.

from_julian : JulianDate -> Date

Retain a validated Julian date with its calendar identity, without conversion.

as_gregorian : Date -> Try(GregorianDate, [UnsupportedCalendar(Calendar)])

Access a stored Gregorian date without converting another calendar. Use in_calendar when conversion, rather than access, is intended.

from_fields : Calendar, Fields -> Try(Date, [OutOfRange, InvalidMonth, InvalidDay])

Validate { year, month, day } in the explicitly selected calendar. Year is astronomical (zero means 1 BCE); month and day are one-based. Invalid month/day combinations and unsupported provider years return structured errors.

from_civil_day : Calendar, CivilDay -> Try(Date, [OutOfRange])

Describe a shared civil-day coordinate in the selected calendar. Return OutOfRange when the date is outside that calendar's supported years.

to_civil_day : Date -> CivilDay

Read the shared civil-day coordinate, allowing equal-day comparison across calendars without introducing a timezone.

calendar : Date -> Calendar

Read the calendar retained by this date description.

to_fields : Date -> Fields

Read year, month and day in the retained calendar. Use in_calendar to convert before reading fields in a different calendar.

in_calendar : Date, Calendar -> Try(Date, [OutOfRange])

Convert to a description of the same civil day in the requested calendar. Return OutOfRange if that day is unsupported by the destination provider.

same_day : Date, Date -> Bool

Equal day extent on the shared civil axis, independent of description.

is_eq : Date, Date -> Bool

Description equality retains calendar identity; use same_day for extents.

to_hash : Date, Hasher -> Hasher

Hash date description identity, including the calendar, consistently with is_eq. Equal civil-day extent alone does not imply equal description hashes.

to_inspect : Date -> Str

Describe the retained Gregorian or Julian date for diagnostics. No timezone or resolved position is inferred.

Fields : { year : I64, month : U8, day : U8 }

Astronomical year and one-based month/day fields in the chosen calendar.

Delta

Calendar.Delta :: # (opaque)

Ordered calendar components, not an elapsed or POSIX displacement. Arithmetic applies years, then months, then civil days.

from_components : Components -> Delta

Construct an ordered calendar displacement from signed years, months and days. Components remain as supplied: twelve months is not normalized to one year.

to_components : Delta -> Components

Read the signed components as described, without applying them to a date or converting them to elapsed time.

is_eq : Delta, Delta -> Bool

Compare component definitions without an anchor; one year is not twelve months.

to_hash : Delta, Hasher -> Hasher

Hash component definitions consistently with equality. One year and twelve months remain distinct descriptions even when an application gives the same result.

to_inspect : Delta -> Str

Bounded component description; no anchor, normalization or elapsed claim.

years : I64 -> Delta

Construct a displacement with the supplied signed year count and zero months/days.

months : I64 -> Delta

Construct a displacement with the supplied signed month count and zero years/days.

days : I64 -> Delta

Construct a displacement with the supplied signed civil-day count and zero years/months.

Components : { years : I64, months : I64, days : I64 }

Signed year, month and civil-day counts, applied in that order.

Value

Calendar.Value :: # (opaque)

A finite civil selection retaining its calendar and supplied resolution. Supports Gregorian/Julian provider years and one to six fractional digits. Minute 12:30 differs from second 12:30:00; .12 differs from .120. Construction validates once in constant work, without choosing a zone or computing an exclusive upper bound. Bounds outside the provider range fail only when requested. Use ZoneRules.calendar_selection_cursor for bounded interpretation, preserving disconnected folds and empty gaps.

year : Calendar, I64 -> Try(Value, [OutOfRange, InvalidMonth, InvalidDay])

Select the whole provider year; year zero is 1 BCE.

month : Calendar, I64, U8 -> Try(Value, [OutOfRange, InvalidMonth, InvalidDay])

Select a whole calendar month; invalid month numbers return InvalidMonth.

day : Date -> Value

Select one validated civil date; no fixed elapsed duration is implied.

hour : Date, U8 -> Try(Value, [InvalidHour, InvalidMinute, InvalidSecond, UnsupportedLeapSecond, InvalidMicrosecond])

Describe the entire local hour beginning at the supplied date and hour. Reject an invalid hour; zone interpretation may later yield disconnected coverage.

minute : Date, U8, U8 -> Try(Value, [InvalidHour, InvalidMinute, InvalidSecond, UnsupportedLeapSecond, InvalidMicrosecond])

Describe the entire local minute on the supplied date. Validate hour/minute fields; omitted seconds locate its start but do not narrow its resolution.

second : Date, U8, U8, U8 -> Try(Value, [InvalidHour, InvalidMinute, InvalidSecond, UnsupportedLeapSecond, InvalidMicrosecond])

Describe the entire local second on the supplied date. Invalid clock fields and unsupported leap seconds return structured errors.

fractional_second : Date, { hour : U8, minute : U8, second : U8 }, { value : U32, digits : U8 } -> Try(Value, [InvalidFraction, UnsupportedPrecision, InvalidHour, InvalidMinute, InvalidSecond, UnsupportedLeapSecond, InvalidMicrosecond])

fraction is the supplied decimal integer: {value: 12, digits: 2} is .12. Zero digits and values requiring more digits are malformed. More than six digits are unsupported, even when trailing zeroes could be discarded.

resolution : Value -> Resolution

Supplied field precision, preserved even when lower fields are zero.

date : Value -> Date

Canonical start components; omitted lower fields are filled only for bounds. Their presence does not mean the caller supplied a complete local label.

clock : Value -> ClockTime

Canonical start clock; pair with date only for explicit label composition.

bounds : Value -> Try({ start : { date : Date, clock : ClockTime }, end : { date : Date, clock : ClockTime } }, [OutOfRange])

Half-open civil selection. O(1), with no zone choice or elapsed-time claim. Year/month bounds use Gregorian/Julian's twelve-month shape explicitly.

is_eq : Value, Value -> Bool

Description equality, including precision and calendar identity.

to_hash : Value, Hasher -> Hasher

Hash calendar, canonical start and supplied resolution consistently with description equality. Equal starts at different resolutions remain distinct keys.

description : Value -> Description

Read calendar, date fields, clock fields and resolution for presentation or semantic explanation. This does not resolve zones or compute an exclusive end.

to_inspect : Value -> Str

Return a bounded diagnostic description preserving calendar and supplied resolution. Use a supported standards adapter for persistence.

Resolution : [Year, Month, Day, Hour, Minute, Second, Fraction(U8)]

Supplied selection width: Year, Month, Day, Hour, Minute, Second or Fraction(digits), where digits is between one and six for valid values.

Description : { calendar : Calendar, fields : Fields, clock : Fields, resolution : Resolution }

Supplied description metadata, without lowering or interpretation.