TimedRecurrence

TimedRecurrence :: # (opaque)

Native Gregorian timed series, in source-label order. Distinct source labels retain their identity even if gap adjustment maps them to one boundary. Windows select source labels, not timeline overlaps. This is not an RRULE parser. COUNT includes chosen source occurrences before the query window; UNTIL is inclusive in local position. Daily through yearly periods use Gregorian selectors via new; new_subdaily supplies hourly, minutely or secondly periods. Source and boundary exclusions apply after interpretation and COUNT; they do not bypass gap/fold validation. Inclusions do not consume COUNT and merge by source position; durations are supplied by TimedSchedule. Boundary exclusions match every selected occurrence at that coordinate, without projecting back to a source label. Clock candidates are ordered by source label. BYSETPOS indexes that full period after explicit interpretation, without deduplicating equal boundaries. Construction retains at most 4096 positions and bounded field selectors. Cursor work follows examined days/clocks and separately budgeted zone segments. Position selection scans at most 4096 supplied positions per item. Without positions, buffering holds one occurrence. With positions it holds the whole interpreted period, subject to max_buffered. Retained cursors can share buffers; resuming a shared buffer can copy it on append.

definition : TimedRecurrence -> Definition

Effective field selectors and source labels, without clock products, occurrence enumeration or interpretation. Immutable lists may be shared. Every candidate retains the microsecond field of the anchor clock. In subdaily rules, empty calendar filter lists leave those fields unrestricted.

from_definition : Definition -> Try(TimedRecurrence, [UnsupportedCalendar(Calendar), InvalidInterval, TooManySelectors, InvalidSelector(Str), InvalidCombination(Str), OutOfRange, InvalidHour, InvalidMinute, InvalidSecond, UnsupportedLeapSecond, InvalidCount, InvalidUntil, InvalidSetPosition, UnsynchronizedStart, ..])

Rebuild an edited declaration through the same checked constructors. Anchor and inclusions must retain Gregorian labels. Exclusions and UNTIL retain native local-position semantics and their calendar descriptions. Boundary exclusions preserve their distinct POSIX domain.

new : { date : GregorianDate, clock : ClockTime }, Spec -> Try(TimedRecurrence, [InvalidInterval, TooManySelectors, InvalidSelector(Str), InvalidCombination(Str), OutOfRange, InvalidHour, InvalidMinute, InvalidSecond, UnsupportedLeapSecond, InvalidCount, InvalidUntil, InvalidSetPosition, UnsynchronizedStart, ..])

Construct a timed calendar recurrence from a Gregorian date and clock anchor. Validate calendar/clock selectors, termination and positions before any zone lookup or occurrence expansion.

new_subdaily : { date : GregorianDate, clock : ClockTime }, SubdailySpec -> Try(TimedRecurrence, [InvalidInterval, TooManySelectors, InvalidSelector(Str), InvalidCombination(Str), OutOfRange, InvalidHour, InvalidMinute, InvalidSecond, UnsupportedLeapSecond, InvalidCount, InvalidUntil, InvalidSetPosition, UnsynchronizedStart, ..])

Construct an hourly, minutely or secondly recurrence from local fields. Frequency-specific clock defaults and calendar filters are checked once; elapsed-time interpretation still requires explicit rules.

with_exclusions : TimedRecurrence, List(LocalDateTime) -> Try(TimedRecurrence, [TooManySelectors, ..])

Replace the source-position exclusion set; an empty list clears it. Equal local positions match across supported calendar descriptions. Do not confuse source equality with equal resolved boundaries in a gap. Inputs plus existing boundary exclusions total at most 4096. O(n log n) normalization, O(log n) membership. Existing cursors retain their original immutable rule and exclusion set.

with_boundary_exclusions : TimedRecurrence, List(PosixBoundary) -> Try(TimedRecurrence, [TooManySelectors, ..])

Replace resolved-boundary exclusions without interpreting source labels. All occurrences selected at a matching boundary are excluded, after COUNT and BYSETPOS, including explicit inclusions. Local exclusions stay distinct. Supplied inputs plus existing local exclusions must total at most 4096. O(n log n) sorting/deduplication; O(log n) membership per occurrence.

with_inclusions : TimedRecurrence, List({ date : GregorianDate, clock : ClockTime }) -> Try(TimedRecurrence, [TooManySelectors, ..])

Replace at most 4096 explicit Gregorian starts, normalized by position. They may precede the anchor or follow COUNT/UNTIL; the query still applies. Duplicate starts merge with the rule, and exclusions win over both. Existing cursors retain their input set. Construction is O(n log n).

add_inclusions : TimedRecurrence, List({ date : GregorianDate, clock : ClockTime }) -> Try(TimedRecurrence, [TooManySelectors, ..])

Add explicit starts while retaining existing inclusions and exclusions. Existing normalized entries plus supplied inputs must total at most 4096 before deduplication. Construction sorts the combined bounded collection.

fact_count : TimedRecurrence -> U64

Effective declaration facts, without clock products or zone evaluation. Clock selectors include normalized defaults; original spelling is absent.

fact_at : TimedRecurrence, U64 -> [End, Item(SemanticFact)]

Read one semantic explanation fact by zero-based index; End means the index is past the declaration’s facts. Does not resolve zones or enumerate occurrences.

to_inspect : TimedRecurrence -> Str

Return a bounded diagnostic summary without advancing cursors or enumerating occurrences. Use typed accessors for application logic; this text is not a storage format.

cursor : TimedRecurrence, Window, Context -> Try(Cursor, [EmptyWindow, ReversedWindow, OutOfRange, ..])

Start a bounded source-window query using explicit immutable rules and fold/gap policies. Reject invalid windows; defer interpretation errors to cursor consumption.

Termination : [Forever, Count(U64), Until(LocalDateTime), UntilBoundary(PosixBoundary)]

Until is inclusive in source-label order. UntilBoundary is inclusive on the POSIX axis after full-period BYSETPOS selection. Explicit inclusions remain outside rule termination. A boundary before all starts yields no rule occurrences; it cannot be compared to the unresolved anchor at new.

Spec : { calendar : Spec, clocks : Spec, termination : Termination, by_set_pos : List(I16) }

Calendar recurrence fields, effective clock selection, termination and BYSETPOS positions. Use the subdaily constructor for frequencies smaller than a day.

Definition : { anchor : LocalDateTime, pattern : [Calendar(Spec), Subdaily({ frequency : Frequency, interval : I64, calendar : Spec })], clocks : Spec, termination : Termination, by_set_pos : List(I16), inclusions : List(LocalDateTime), exclusions : List(LocalDateTime), boundary_exclusions : List(PosixBoundary) }

Window-free native declaration retaining anchor precision, effective selectors and separate local-source and boundary exclusions. This is an editing interface, not a standardized storage document.

SubdailySpec : { pattern : Spec, termination : Termination, by_set_pos : List(I16) }

Subdaily period/filter specification, termination and positions. Candidate clocks retain the anchor microsecond field.

Window : { start : LocalDateTime, end : LocalDateTime }

Half-open window of original local source starts. Querying another window does not reset the anchored series COUNT.

Context : { rules : ZoneRules, occurrence : OccurrencePolicy, gap : [RejectGap, UseOffsetBeforeGap] }

Immutable zone rules and explicit fold/gap policies for generated starts. No machine zone or implicit occurrence choice is supplied.

Limits : { max_steps : U64, max_buffered : U64, max_zone_segments : U64, max_zone_candidates : U64 }

Per-call candidate steps, interpreted-period buffer, zone segments and zone candidates. Exhaustion returns a resumable limit rather than an empty success.

Limit : [WorkLimit, BufferLimit, ZoneWorkLimit, ZoneBufferLimit, OutputLimit]

Which candidate or zone budget prevented completion. OutputLimit also indicates a full output page; resume to determine whether more values exist.

Occurrence

TimedRecurrence.Occurrence :: # (opaque)

A selected recurrence start retaining source identity separately from its resolved boundary and any gap adjustment.

source : Occurrence -> LocalDateTime

Return the original local source label. A gap adjustment never replaces this identity with its projected wall-clock label.

boundary : Occurrence -> PosixBoundary

Return the selected POSIX boundary. Different source labels can select the same boundary.

adjustment : Occurrence -> [Exact, BeforeGap(GapTransition)]

Report exact resolution or the forward gap whose before-offset policy selected this boundary.

rules : Occurrence -> ZoneRules

Return the immutable rules used to resolve this occurrence, suitable for consistent interpretation of its ending.

to_inspect : Occurrence -> Str

Return a bounded diagnostic summary without advancing cursors or enumerating occurrences. Use typed accessors for application logic; this text is not a storage format.

Next : { steps : U64, zone_segments : U64, buffered : U64, zone_buffered : U64, status : [End, Item({ occurrence : Occurrence, cursor : Cursor }), Limited({ cursor : Cursor, reason : Limit })] }

One interpreted source occurrence with continuation, End, or Limited progress. Counters expose candidate and zone work for the call.

CollectLimits : { work : Limits, max_occurrences : U64 }

Candidate/zone work limits plus the maximum number of occurrences returned in this batch.

Batch : { occurrences : List(Occurrence), steps : U64, zone_segments : U64, buffered : U64, zone_buffered : U64, status : [Complete, Limited({ cursor : Cursor, reason : Limit })] }

Interpreted starts with resource accounting and completion status. Limited carries the cursor preserving COUNT, position selection and exceptions.

Cursor

TimedRecurrence.Cursor :: # (opaque)

Resumable recurrence execution state for one source window and immutable context. Keep it intact across limited queries.

next : Cursor, Limits -> Try(Next, [OutOfRange, OutsideValidity, Gap, Ambiguous, AmbiguousGap, OffsetConflict, UnsynchronizedStart, ..])

Work counts date tests, clock candidates, period boundaries and emitted/filtered candidates. Zone work has a separate total budget. BYSETPOS buffers the whole period and validates DTSTART's position before any first-period output. Without BYSETPOS, only one pending occurrence is retained. Caller-retained cursors may share buffers. Merge explicit starts after rule selection/COUNT, retaining at most one rule lookahead and one pending inclusion classification. Looking ahead may examine a full BYSETPOS period under the same budgets.

collect : Cursor, CollectLimits -> Try(Batch, [OutOfRange, OutsideValidity, Gap, Ambiguous, AmbiguousGap, OffsetConflict, UnsynchronizedStart, ..])

Budgets apply to the entire batch, not separately to each output. Output capacity is a separate bound from pending candidate buffers. At capacity return Limited(OutputLimit) without looking ahead; even an exactly full final batch needs resumption to prove completion.

outcomes : Cursor, Limits -> Iter(Try(Next, [OutOfRange, OutsideValidity, Gap, Ambiguous, AmbiguousGap, OffsetConflict, UnsynchronizedStart]))

A lazy stream of next outcomes. Budgets apply per advancement. End, errors and Limited are terminal items. Resume a Limited cursor explicitly; iterating a zero-work stream cannot retry forever.

to_inspect : Cursor -> Str

Return a bounded diagnostic summary without advancing cursors or enumerating occurrences. Use typed accessors for application logic; this text is not a storage format.