ICalPeriod

ICalPeriod :: # (opaque)

RFC 5545 section 3.3.9 PERIOD values, profile period-values-v1. Parse an extracted start/end or start/positive-duration value. Endpoint values share ICalDateTime's year, precision and leap-second profile. Both explicit endpoints must use the same UTC/local form; mixed forms are outside this profile. Property parameters, comma lists and ICS content lines belong to the calling adapter. Source spelling is not retained.

Parsing visits at most 273 bytes and does no zone work. UTC endpoint order is checked immediately. Local endpoint order is checked after interpretation: increasing labels can resolve to equal or reversed boundaries near a gap. Canonical text preserves explicit-end versus duration intent. See the reservation application for native rule execution with parsed period additions.

import time.ICalPeriod
expect {
    value = ICalPeriod.parse("19970101T180000Z/PT5H30M")?
    ICalPeriod.to_text(value) == "19970101T180000Z/PT19800S"
}
parser_for : encoding -> (state -> Try({ value : ICalPeriod, rest : state }, [InvalidICalPeriod(Error), Encoding(err)]))
    where [
        encoding.parse_str : encoding, state -> Try({ value : Str, rest : state }, err),
    ]

Decode one encoded string using this type's text parser. Encoding failures remain distinct from this profile's validation errors. The encoding owns framing and its work limits; parse bounds the decoded text.

encoder_for : encoding -> (ICalPeriod, state -> Try(state, err))
    where [
        encoding.encode_str : Str, state -> Try(state, err),
    ]

Encodes the canonical standard text as a string in the selected encoding; encoding failures pass through.

from_quote : Str -> Try(ICalPeriod, [BadQuotedBytes(Str)])

Typed quoted literals use the same checked profile at compile time. Runtime interpolation remains Str followed by an explicit parse call.

profile : Str

Identifier of the supported text profile described above; it does not imply support for the entire standard.

parse : Str -> Try(ICalPeriod, Error)

Parses start/end or start/duration. UTC ordering is checked now; local ending order is checked when the period is interpreted.

start : ICalPeriod -> ICalDateTime

The retained starting DATE-TIME declaration; no zone interpretation is performed.

ending : ICalPeriod -> Ending

The retained explicit endpoint or duration, preserving the original ending intent.

to_text : ICalPeriod -> Str

Canonical start/end or start/duration value. Duration units may normalize, but explicit-end versus duration intent remains distinct.

is_eq : ICalPeriod, ICalPeriod -> Bool

Compares the start and ending declarations, including UTC/local form and duration-versus-endpoint intent.

to_hash : ICalPeriod, Hasher -> Hasher

Hashes the same declaration fields used by is_eq, so equal values are interchangeable as dictionary keys.

fact_count : ICalPeriod -> U64

These are source-declaration facts, not a resolved span. Local endpoint ordering remains unresolved; a duration ending is not added to its start.

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

Returns the zero-based semantic fact, or End when the index is outside fact_count. Facts describe meaning, not a serialized record.

to_inspect : ICalPeriod -> Str

A concise semantic summary for debugging. Use the standard text encoder for storage or interchange.

schedule : id, TimedRecurrence, Window, ICalDuration, List(ICalPeriod), Context -> Try(TimedSchedule(id), [TooManyPeriods, IncompatibleContext, TooManySelectors, InvalidDuration, EmptyWindow, ReversedWindow, OutOfRange, TooManyOverrides, ConflictingEnding(LocalDateTime)])

Add at most 4096 PERIOD inclusions to a native rule, preserving its existing inclusions, COUNT/UNTIL and source exclusions. Native inclusion capacity also bounds the combined inputs before deduplication. Repeated equal definitions coalesce; conflicting endings at one source fail even when excluded or outside the query. This profile never picks a winner. The context explicitly assigns meaning to the native rule's source labels and window. All periods must match that UTC/local form. Local rules are supplied immutable data, not a TZID lookup. Both starts and local ends use first-fold/before-gap RFC policies. UTC uses fixed zero-offset POSIX rules on [I64.lowest, I64.highest), without leap-second positions. Native rule ranges remain native ranges; the text parser limits only supplied periods. No recurrence or zone work is done here; the returned TimedSchedule uses its ordinary budgets and resumptions. Construction is O(n log n), with bounded input buffers; not a full RRULE parser or an ICS property adapter. Existing duration overrides must be supplied together as periods rather than merged from another schedule.

prepare : TimedRecurrence, ICalDuration, List(ICalPeriod), Context -> Try({ rule : TimedRecurrence, endings : Endings, context : Context }, [TooManyPeriods, IncompatibleContext, TooManySelectors, InvalidDuration, OutOfRange, TooManyOverrides, ConflictingEnding(LocalDateTime)])

Advanced preparation without a query window or occurrence enumeration. Returns checked TimedSchedule.Endings for reuse with from_prepared. The calling wrapper retains original PERIOD declarations for export; this execution record alone is not a standard storage representation.

Ending : [End(ICalDateTime), Duration(ICalDuration)]

Preserves whether the period ends at an explicit DATE-TIME or after a positive duration; these intents are not interchangeable near zone transitions.

Context : [Utc, Local(ZoneRules)]

Utc interprets Z values without caller-supplied rules. Local supplies the immutable rules for local labels, including floating values interpreted by the caller.

Error : [Malformed, TooLarge, Start(Error), End(Error), Duration(Error), MixedForms, InvalidPeriod]

Reports which endpoint or duration failed, mixed UTC/local forms, invalid UTC ordering, syntax or input size.