rrule_lab

    An explainable RFC 5545 recurrence rule engine written in MoonBit

    calendar
    rrule
    rfc5545
    scheduler
    Download zip
    Author
    Version
    0.1.0
    License
    Apache-2.0
    Last updated
    2 months ago
    Downloads
    29

    No dependencies

    #RRuleLab

    CI License

    RRuleLab 是一个使用 MoonBit 原创实现的、可解释且可审计的 RFC 5545 重复规则引擎。它把 RRULE、RDATE、EXDATE 转换为确定的时间序列,并进一步回答“规则为什么这样运行”“修改规则会影响哪些日期”“多个日程是否冲突”等问题。

    项目面向日历、预约、排班、提醒、维护窗口和自动化任务。它不是 MoonBit 编译器周边工具,也不是普通 cron 解析器;核心差异在于 RFC 5545 语义、行为级差异分析和可解释日程审计。

    #功能

    • 解析、校验、规范化并序列化 RFC 5545 RRULE
    • 支持 SECONDLY 到 YEARLY、主要 BY* 过滤器、负序号及 BYSETPOS
    • 在有界窗口内安全展开规则,带结果与迭代上限
    • 合并 DTSTART、多个 RRULE、RDATE 与 EXDATE
    • 读取与生成 recurrence 相关的 iCalendar/VEVENT 子集
    • 中英文规则解释、字段级诊断与修复建议
    • 比较两个规则的新增、删除、共有实例及首次分歧
    • 审计重复实例、周末、非工作时段、过密计划和间隔分布
    • 检测带持续时间事件的区间冲突,计算忙碌窗口与空闲窗口
    • ISO 8601 持续时间和节假日感知的业务日历调整
    • 可作为 MoonBit 库使用,也提供可运行 CLI

    #五分钟开始

    需要 MoonBit 工具链。在仓库根目录执行:

    moon check moon test moon run cmd/rrule_lab -- demo

    规范化并解释规则:

    moon run cmd/rrule_lab -- normalize "RRULE:FREQ=WEEKLY;BYDAY=WE,MO,MO" moon run cmd/rrule_lab -- explain "FREQ=MONTHLY;BYDAY=-1FR" zh

    展开一个真实日程:

    moon run cmd/rrule_lab -- expand \ 20260801T090000 \ "FREQ=WEEKLY;COUNT=6;BYDAY=MO,WE,FR" \ 20260801T000000 \ 20260901T000000 \ 20

    审计日程或比较规则变更:

    moon run cmd/rrule_lab -- audit 20260801T080000 \ "FREQ=DAILY;COUNT=5" 20260801T000000 20260810T000000 moon run cmd/rrule_lab -- diff 20260801T090000 \ "FREQ=DAILY;COUNT=6" \ "FREQ=DAILY;INTERVAL=2;COUNT=6" \ 20260801T000000 20260820T000000

    完整命令列表:

    moon run cmd/rrule_lab -- help

    #库 API 示例

    let start = @rrule_lab.parse_datetime("20260803T093000")
    let rule = @rrule_lab.parse_rrule("FREQ=WEEKLY;COUNT=8;BYDAY=MO,WE,FR")
    let options = @rrule_lab.ExpansionOptions::new(
    @rrule_lab.parse_datetime("20260801T000000"),
    @rrule_lab.parse_datetime("20260901T000000"),
    limit=20,
    )
    let occurrences = @rrule_lab.expand_rrule(start, rule, options)
    let audit = @rrule_lab.audit_occurrences(occurrences)
    println(audit.to_text())

    在其他 MoonBit 项目中使用发布版本:

    moon add cjkzD/rrule_lab

    #工程质量

    • 主要实现语言:MoonBit
    • 有效 MoonBit 源码:4053 行(包含测试,不包含 _build)
    • 自动化测试:51 项,覆盖 Wasm 与 JavaScript 目标
    • CI:检查、测试、构建、格式、CLI 示例、代码规模门禁
    • 许可证:Apache-2.0;运行时仅依赖 MoonBit 官方 core
    • 开发记录:真实功能拆分提交,保留架构、变更与发布说明

    #功能边界

    首个版本专注本地日期时间与 recurrence 语义,不包含 CalDAV 同步、完整 IANA 时区数据库、自然语言模型解析或完整 iCalendar 全组件支持。浮动本地时间与时区换算明确分层,避免在规则运算中隐式引入环境差异。

    #许可证

    Copyright 2026 cjkzD。根据 Apache License 2.0 开源。

    BusinessCalendarError

    pub suberror BusinessCalendarError {
    EmptyWorkingWeek
    SearchLimitExceeded(Date, Int)
    } derive(Eq,
    Debug
    )

    CliError

    pub suberror CliError {
    MissingArgument(String)
    InvalidNumber(String, String)
    UnknownCommand(String)
    InvalidLanguage(String)
    } derive(Eq,
    Debug
    )

    DateTimeError

    pub suberror DateTimeError {
    InvalidDate(Int, Int, Int)
    InvalidTime(Int, Int, Int)
    InvalidFormat(String)
    } derive(Eq,
    Debug
    )

    DurationError

    pub suberror DurationError {
    EmptyDuration
    MissingDesignator
    MissingNumber(Int)
    InvalidCharacter(Int, Int)
    DuplicateUnit(String)
    UnitOutOfOrder(String)
    DateUnitInTimePart(String)
    TimeUnitInDatePart(String)
    FractionUnsupported
    NonFixedCalendarUnit
    } derive(Eq,
    Debug
    )

    EventSlotError

    pub suberror EventSlotError {
    NonPositiveDuration
    } derive(Eq,
    Debug
    )

    ExpansionError

    pub suberror ExpansionError {
    InvalidRule(Array[Diagnostic])
    InvalidWindow
    InvalidLimit(Int)
    IterationLimitExceeded(Int)
    } derive(
    Debug
    )

    ICalendarError

    pub suberror ICalendarError {
    MissingStart
    InvalidContentLine(String)
    UnsupportedProperty(String)
    InvalidDateValue(String)
    } derive(Eq,
    Debug
    )

    RRuleParseError

    pub suberror RRuleParseError {
    EmptyRule
    InvalidPart(String)
    DuplicateField(String)
    MissingFrequency
    UnknownFrequency(String)
    InvalidInteger(String, String)
    InvalidWeekday(String)
    InvalidUntil(String)
    InvalidValue(String, String)
    } derive(Eq,
    Debug
    )

    TimeRangeError

    pub suberror TimeRangeError {
    EmptyOrReversedRange(DateTime, DateTime)
    } derive(Eq,
    Debug
    )

    AuditFinding

    pub struct AuditFinding {
    severity : AuditSeverity
    code : String
    message : String
    evidence : Array[DateTime]
    suggestion : String
    } derive(Eq,
    Debug
    )

    A stable finding code plus human-readable evidence and remediation.

    AuditSeverity

    pub(all) enum AuditSeverity {
    AuditInfo
    AuditWarning
    AuditError
    } derive(Compare, Eq,
    Debug
    )

    Severity used by schedule audit findings.

    AuditSeverity::label

    fn AuditSeverity::label(self : AuditSeverity) -> String

    BusinessCalendar

    pub struct BusinessCalendar {
    name : String
    working_weekdays : Array[Weekday]
    holidays : Array[Date]
    } derive(Eq,
    Debug
    )

    Named workweek and holiday set. Dates are local calendar dates; no timezone assumptions are introduced by business-day adjustment.

    BusinessCalendar::add_business_days

    fn BusinessCalendar::add_business_days(self : BusinessCalendar, date : Date, amount : Int) -> Date raise BusinessCalendarError

    BusinessCalendar::add_holiday

    fn BusinessCalendar::add_holiday(self : BusinessCalendar, date : Date) -> BusinessCalendar

    BusinessCalendar::adjust

    fn BusinessCalendar::adjust(self : BusinessCalendar, date : Date, convention : BusinessDayConvention) -> Date raise BusinessCalendarError

    BusinessCalendar::adjust_datetime

    BusinessCalendar::adjust_occurrences

    fn BusinessCalendar::adjust_occurrences(self : BusinessCalendar, values : Array[DateTime], convention : BusinessDayConvention, deduplicate? : Bool) -> Array[BusinessDayAdjustment] raise BusinessCalendarError

    BusinessCalendar::count_business_days

    fn BusinessCalendar::count_business_days(self : BusinessCalendar, start : Date, finish : Date) -> Int

    Count working dates in the half-open interval [start, finish).

    BusinessCalendar::is_holiday

    fn BusinessCalendar::is_holiday(self : BusinessCalendar, date : Date) -> Bool

    BusinessCalendar::is_working_day

    fn BusinessCalendar::is_working_day(self : BusinessCalendar, date : Date) -> Bool

    BusinessCalendar::new

    fn BusinessCalendar::new(name : String, working_weekdays? : Array[Weekday], holidays? : Array[Date]) -> BusinessCalendar raise BusinessCalendarError

    BusinessCalendar::next_working_date

    fn BusinessCalendar::next_working_date(self : BusinessCalendar, date : Date, include_current? : Bool, search_limit? : Int) -> Date raise BusinessCalendarError

    BusinessCalendar::previous_working_date

    fn BusinessCalendar::previous_working_date(self : BusinessCalendar, date : Date, include_current? : Bool, search_limit? : Int) -> Date raise BusinessCalendarError

    BusinessCalendar::remove_holiday

    fn BusinessCalendar::remove_holiday(self : BusinessCalendar, date : Date) -> BusinessCalendar

    BusinessCalendar::to_text

    fn BusinessCalendar::to_text(self : BusinessCalendar) -> String

    Describe the calendar in a stable, diff-friendly text format.

    BusinessCalendar::with_working_weekdays

    fn BusinessCalendar::with_working_weekdays(self : BusinessCalendar, working_weekdays : Array[Weekday]) -> BusinessCalendar raise BusinessCalendarError

    BusinessCalendar::working_dates_between

    fn BusinessCalendar::working_dates_between(self : BusinessCalendar, start : Date, finish : Date) -> Array[Date]

    BusinessDayAdjustment

    pub struct BusinessDayAdjustment {
    original : DateTime
    adjusted : DateTime
    changed : Bool
    convention : BusinessDayConvention
    } derive(Eq,
    Debug
    )

    BusinessDayConvention

    pub(all) enum BusinessDayConvention {
    Unadjusted
    Following
    ModifiedFollowing
    Preceding
    ModifiedPreceding
    } derive(Compare, Eq,
    Debug
    )

    Convention used when an occurrence lands on a non-working date.

    BusinessDayConvention::label

    fn BusinessDayConvention::label(self : BusinessDayConvention) -> String

    ByDay

    pub struct ByDay {
    ordinal : Int?
    weekday : Weekday
    } derive(Compare, Eq,
    Debug
    )

    A weekday optionally qualified with an ordinal such as 1MO or -1FR.

    ByDay::new

    fn ByDay::new(weekday : Weekday, ordinal? : Int) -> ByDay

    ByDay::to_string

    fn ByDay::to_string(self : ByDay) -> String

    ChangeImpact

    pub struct ChangeImpact {
    baseline_count : Int
    candidate_count : Int
    added : Array[DateTime]
    removed : Array[DateTime]
    unchanged : Array[DateTime]
    first_divergence : DateTime?
    similarity_permille : Int
    } derive(Eq,
    Debug
    )

    Behavioral impact of replacing one rule with another over a finite horizon.

    CliResult

    pub struct CliResult {
    exit_code : Int
    stdout : String
    stderr : String
    } derive(Eq,
    Debug
    )

    Date

    pub struct Date {
    year : Int
    month : Int
    day : Int
    } derive(Compare, Eq,
    Debug
    )

    A proleptic Gregorian calendar date.

    Date::add_days

    fn Date::add_days(self : Date, amount : Int) -> Date

    Date::add_months

    fn Date::add_months(self : Date, amount : Int) -> Date

    Date::add_years

    fn Date::add_years(self : Date, amount : Int) -> Date

    Date::day_of_year

    fn Date::day_of_year(self : Date) -> Int

    Date::new

    fn Date::new(year : Int, month : Int, day : Int) -> Date raise DateTimeError

    Date::to_epoch_day

    fn Date::to_epoch_day(self : Date) -> Int

    Howard Hinnant's civil calendar conversion, shifted to Unix epoch days.

    Date::to_iso_string

    fn Date::to_iso_string(self : Date) -> String

    Date::weekday

    fn Date::weekday(self : Date) -> Weekday

    DateTime

    pub struct DateTime {
    date : Date
    time : Time
    } derive(Compare, Eq,
    Debug
    )

    A local date and time. RRuleLab deliberately keeps local time separate from time-zone conversion so recurrence arithmetic remains deterministic.

    DateTime::add_days

    fn DateTime::add_days(self : DateTime, amount : Int) -> DateTime

    DateTime::add_duration

    fn DateTime::add_duration(self : DateTime, duration : Duration) -> DateTime

    DateTime::add_months

    fn DateTime::add_months(self : DateTime, amount : Int) -> DateTime

    DateTime::add_seconds

    fn DateTime::add_seconds(self : DateTime, amount : Int64) -> DateTime

    DateTime::add_years

    fn DateTime::add_years(self : DateTime, amount : Int) -> DateTime

    DateTime::new

    fn DateTime::new(year : Int, month : Int, day : Int, hour : Int, minute : Int, second : Int) -> DateTime raise DateTimeError

    DateTime::to_epoch_second

    fn DateTime::to_epoch_second(self : DateTime) -> Int64

    DateTime::to_iso_string

    fn DateTime::to_iso_string(self : DateTime) -> String

    Diagnostic

    pub struct Diagnostic {
    severity : Severity
    code : String
    field : String
    message : String
    suggestion : String?
    } derive(Eq,
    Debug
    )

    Machine-readable and human-friendly diagnostic returned by validation.

    Duration

    pub struct Duration {
    years : Int
    months : Int
    weeks : Int
    days : Int
    hours : Int
    minutes : Int
    seconds : Int
    negative : Bool
    } derive(Eq,
    Debug
    )

    A calendar-aware ISO 8601 duration. Years and months are retained as calendar units; weeks, days and clock fields can also be reduced to seconds.

    Duration::explain_en

    fn Duration::explain_en(self : Duration) -> String

    Produce a compact English explanation suitable for reports and CLI output.

    Duration::explain_zh

    fn Duration::explain_zh(self : Duration) -> String

    Duration::fixed_seconds

    fn Duration::fixed_seconds(self : Duration) -> Int64 raise DurationError

    Duration::has_calendar_units

    fn Duration::has_calendar_units(self : Duration) -> Bool

    Duration::is_zero

    fn Duration::is_zero(self : Duration) -> Bool

    Duration::new

    fn Duration::new(years? : Int, months? : Int, weeks? : Int, days? : Int, hours? : Int, minutes? : Int, seconds? : Int, negative? : Bool) -> Duration

    Duration::sign

    fn Duration::sign(self : Duration) -> Int

    Duration::to_iso_string

    fn Duration::to_iso_string(self : Duration) -> String

    Duration::zero

    fn Duration::zero() -> Duration

    EventSlot

    pub struct EventSlot {
    schedule : String
    ordinal : Int
    start : DateTime
    finish : DateTime
    } derive(Eq,
    Debug
    )

    One occurrence represented as a half-open [start, finish) interval.

    ExpansionOptions

    pub struct ExpansionOptions {
    window_start : DateTime
    window_end : DateTime
    limit : Int
    iteration_limit : Int
    } derive(Eq,
    Debug
    )

    Bounds and safety limits for a recurrence expansion request.

    ExpansionOptions::new

    fn ExpansionOptions::new(window_start : DateTime, window_end : DateTime, limit? : Int, iteration_limit? : Int) -> ExpansionOptions

    Frequency

    pub enum Frequency {
    Secondly
    Minutely
    Hourly
    Daily
    Weekly
    Monthly
    Yearly
    } derive(Compare, Eq,
    Debug
    )

    Frequency ordered from the smallest to the largest recurrence period.

    Frequency::code

    fn Frequency::code(self : Frequency) -> String

    RRule

    pub struct RRule {
    frequency : Frequency
    interval : Int
    count : Int?
    until : DateTime?
    week_start : Weekday
    by_second : Array[Int]
    by_minute : Array[Int]
    by_hour : Array[Int]
    by_day : Array[ByDay]
    by_month_day : Array[Int]
    by_year_day : Array[Int]
    by_week_number : Array[Int]
    by_month : Array[Int]
    by_set_position : Array[Int]
    } derive(Eq,
    Debug
    )

    A fully typed subset of RFC 5545 RECUR. Empty arrays mean that the corresponding BY rule is absent and DTSTART supplies the default.

    RRule::explain_en

    fn RRule::explain_en(self : RRule) -> String

    RRule::explain_zh

    fn RRule::explain_zh(self : RRule) -> String

    RRule::is_valid

    fn RRule::is_valid(self : RRule) -> Bool

    RRule::new

    fn RRule::new(frequency : Frequency) -> RRule

    RRule::normalize

    fn RRule::normalize(self : RRule) -> RRule

    RRule::to_string

    fn RRule::to_string(self : RRule) -> String

    RRule::validate

    fn RRule::validate(self : RRule) -> Array[Diagnostic]

    RecurrenceSet

    pub struct RecurrenceSet {
    start : DateTime
    rules : Array[RRule]
    include_dates : Array[DateTime]
    exclude_dates : Array[DateTime]
    } derive(Eq,
    Debug
    )

    A calendar recurrence set combines one or more rules and explicit dates, then removes exception dates. This mirrors RFC 5545 recurrence semantics.

    RecurrenceSet::add_date

    fn RecurrenceSet::add_date(self : RecurrenceSet, value : DateTime) -> RecurrenceSet

    RecurrenceSet::add_rule

    fn RecurrenceSet::add_rule(self : RecurrenceSet, rule : RRule) -> RecurrenceSet

    RecurrenceSet::exclude_date

    fn RecurrenceSet::exclude_date(self : RecurrenceSet, value : DateTime) -> RecurrenceSet

    RecurrenceSet::expand

    RecurrenceSet::new

    RecurrenceSet::to_ical

    fn RecurrenceSet::to_ical(self : RecurrenceSet, uid? : String) -> String

    RuleDifference

    pub struct RuleDifference {
    only_left : Array[DateTime]
    only_right : Array[DateTime]
    shared : Array[DateTime]
    } derive(Eq,
    Debug
    )

    ScheduleAudit

    pub struct ScheduleAudit {
    occurrence_count : Int
    unique_count : Int
    duplicate_count : Int
    weekend_count : Int
    outside_business_hours_count : Int
    first_occurrence : DateTime?
    last_occurrence : DateTime?
    minimum_gap_seconds : Int64?
    maximum_gap_seconds : Int64?
    average_gap_seconds : Int64?
    longest_daily_streak : Int
    weekday_histogram : WeekdayHistogram
    findings : Array[AuditFinding]
    } derive(Eq,
    Debug
    )

    Summary metrics and findings produced for one expanded recurrence set.

    ScheduleAudit::to_text

    fn ScheduleAudit::to_text(self : ScheduleAudit) -> String

    Stable plain-text report intended for terminals, issues and CI logs.

    ScheduleCollision

    pub struct ScheduleCollision {
    left : EventSlot
    right : EventSlot
    overlap_start : DateTime
    overlap_finish : DateTime
    overlap_seconds : Int64
    } derive(Eq,
    Debug
    )

    SetOperation

    pub(all) enum SetOperation {
    Union
    Intersection
    Difference
    } derive(Eq,
    Debug
    )

    Severity

    pub(all) enum Severity {
    Error
    Warning
    Information
    } derive(Compare, Eq,
    Debug
    )

    Time

    pub struct Time {
    hour : Int
    minute : Int
    second : Int
    } derive(Compare, Eq,
    Debug
    )

    Clock time without a time-zone offset.

    Time::new

    fn Time::new(hour : Int, minute : Int, second : Int) -> Time raise DateTimeError

    Time::to_iso_string

    fn Time::to_iso_string(self : Time) -> String

    TimeRange

    pub struct TimeRange {
    start : DateTime
    finish : DateTime
    } derive(Eq,
    Debug
    )

    Half-open time range [start, finish). This representation makes adjacent windows composable without double-counting their shared endpoint.

    TimeRange::contains

    fn TimeRange::contains(self : TimeRange, value : DateTime) -> Bool

    TimeRange::duration_seconds

    fn TimeRange::duration_seconds(self : TimeRange) -> Int64

    TimeRange::intersection

    fn TimeRange::intersection(self : TimeRange, other : TimeRange) -> TimeRange?

    TimeRange::is_adjacent

    fn TimeRange::is_adjacent(self : TimeRange, other : TimeRange) -> Bool

    TimeRange::merge

    fn TimeRange::merge(self : TimeRange, other : TimeRange) -> TimeRange?

    TimeRange::new

    fn TimeRange::new(start : DateTime, finish : DateTime) -> TimeRange raise TimeRangeError

    TimeRange::overlaps

    fn TimeRange::overlaps(self : TimeRange, other : TimeRange) -> Bool

    TimeRange::to_text

    fn TimeRange::to_text(self : TimeRange) -> String

    Weekday

    pub enum Weekday {
    Monday
    Tuesday
    Wednesday
    Thursday
    Friday
    Saturday
    Sunday
    } derive(Compare, Eq,
    Debug
    )

    Days of the week use ISO order (Monday first).

    Weekday::code

    fn Weekday::code(self : Weekday) -> String

    Weekday::iso_number

    fn Weekday::iso_number(self : Weekday) -> Int

    WeekdayHistogram

    pub struct WeekdayHistogram {
    monday : Int
    tuesday : Int
    wednesday : Int
    thursday : Int
    friday : Int
    saturday : Int
    sunday : Int
    } derive(Eq,
    Debug
    )

    Distribution of recurrence instances over ISO weekdays.

    WeekdayHistogram::empty

    WeekdayHistogram::total

    fn WeekdayHistogram::total(self : WeekdayHistogram) -> Int

    WeekdayHistogram::weekend_total

    fn WeekdayHistogram::weekend_total(self : WeekdayHistogram) -> Int

    analyze_rule_change

    fn analyze_rule_change(start : DateTime, baseline : RRule, candidate : RRule, options : ExpansionOptions) -> ChangeImpact raise ExpansionError

    Compare rule behavior using occurrence sets rather than textual syntax.

    audit_occurrences

    fn audit_occurrences(values : Array[DateTime], business_start_hour? : Int, business_end_hour? : Int, expected_minimum? : Int, dense_gap_threshold_seconds? : Int64) -> ScheduleAudit

    Analyze concrete occurrence data and return reproducible findings.

    audit_rule

    fn audit_rule(start : DateTime, rule : RRule, options : ExpansionOptions, business_start_hour? : Int, business_end_hour? : Int) -> ScheduleAudit raise ExpansionError

    Expand and audit a recurrence rule in one bounded operation.

    business_day_convention_from_string

    fn business_day_convention_from_string(text : String) -> BusinessDayConvention?

    cli_help

    fn cli_help() -> String

    combine_occurrences

    fn combine_occurrences(left : Array[DateTime], right : Array[DateTime], operation : SetOperation) -> Array[DateTime]

    compare_rules

    fn compare_rules(start : DateTime, left : RRule, right : RRule, options : ExpansionOptions) -> RuleDifference raise ExpansionError

    date_from_epoch_day

    fn date_from_epoch_day(epoch_day : Int) -> Date

    days_in_month

    fn days_in_month(year : Int, month : Int) -> Int

    detect_collisions

    fn detect_collisions(left : Array[EventSlot], right : Array[EventSlot]) -> Array[ScheduleCollision]

    Detect interval collisions between two named schedules. Touching endpoints are not collisions because event slots use half-open interval semantics.

    duration_between

    fn duration_between(start : DateTime, finish : DateTime) -> Duration

    execute_cli

    fn execute_cli(args : Array[String]) -> CliResult

    Execute one CLI command without performing process I/O. This design makes the command interface fully testable and portable across Wasm and JS.

    expand

    fn expand(start : DateTime, rule_source : String, window_start : DateTime, window_end : DateTime, limit? : Int) -> Array[DateTime] raise

    expand_rrule

    fn expand_rrule(start : DateTime, rule : RRule, options : ExpansionOptions) -> Array[DateTime] raise ExpansionError

    Expand a recurrence within a half-open time window [start, end).

    free_time_ranges

    fn free_time_ranges(bounds : TimeRange, busy : Array[TimeRange]) -> Array[TimeRange]

    Find free half-open windows inside bounds after normalizing busy ranges.

    frequency_from_code

    fn frequency_from_code(code : String) -> Frequency?

    is_leap_year

    fn is_leap_year(year : Int) -> Bool

    make_event_slots

    fn make_event_slots(schedule : String, starts : Array[DateTime], duration : Duration) -> Array[EventSlot] raise

    merge_time_ranges

    fn merge_time_ranges(values : Array[TimeRange], merge_adjacent? : Bool) -> Array[TimeRange]

    Merge overlapping ranges and, by default, directly adjacent ranges.

    parse_basic_date

    fn parse_basic_date(text : String) -> Date raise DateTimeError

    parse_date

    fn parse_date(text : String) -> Date raise DateTimeError

    parse_datetime

    fn parse_datetime(text : String) -> DateTime raise DateTimeError

    parse_duration

    fn parse_duration(source : String) -> Duration raise DurationError

    Parse the integer subset of ISO 8601 durations, including leading minus. Supported examples include P2W, P1Y2M3DT4H5M6S and -PT90S.

    parse_ical_recurrence

    fn parse_ical_recurrence(source : String) -> RecurrenceSet raise

    Parse the recurrence-related subset of an iCalendar component.

    parse_rrule

    fn parse_rrule(source : String) -> RRule raise RRuleParseError

    Parse an RFC 5545 recurrence rule. The optional RRULE: prefix is accepted.

    parse_time

    fn parse_time(text : String) -> Time raise DateTimeError

    ranges_total_seconds

    fn ranges_total_seconds(values : Array[TimeRange]) -> Int64

    version

    fn version() -> String

    Return the semantic version of the RRuleLab library.

    weekday_from_code

    fn weekday_from_code(code : String) -> Weekday?