RecurrenceService
Parse, validate, and materialize RFC 5545 recurrence rules
Overview
RecurrenceService handles RRULE parsing, validation, and expansion of recurring events into concrete occurrences. It uses the rrule library internally.
import { RecurrenceService } from '@hfu.digital/coursekit-nestjs';Methods
parseRule
Parse an RRULE string into an RRule instance.
parseRule(rruleString: string, dtstart: Date): RRule| Parameter | Type | Description |
|---|---|---|
rruleString | string | RFC 5545 RRULE string (e.g., 'FREQ=WEEKLY;BYDAY=MO') |
dtstart | Date | The start date for the recurrence series |
Throws if the RRULE string is invalid.
const rule = recurrence.parseRule('FREQ=WEEKLY;BYDAY=MO,WE,FR', new Date('2026-03-02'));validateRule
Validate an RRULE string without parsing it fully.
validateRule(rruleString: string): string | nullReturns null if valid, or an error message string if invalid.
const error = recurrence.validateRule('FREQ=WEEKLY;BYDAY=MO');
// null (valid)
const error2 = recurrence.validateRule('FREQ=INVALID');
// "Invalid frequency: INVALID"materialize
Expand a recurring event into concrete occurrences for a date range. Applies all exceptions (cancellations, modifications, additions).
materialize(
event: TimetableEvent,
exceptions: EventException[],
dateRange: DateRange,
): MaterializedOccurrence[]| Parameter | Type | Description |
|---|---|---|
event | TimetableEvent | The event to expand |
exceptions | EventException[] | Exceptions to apply |
dateRange | DateRange | The date range to expand within |
Returns an array of MaterializedOccurrence sorted by start time.
Exception handling:
cancelledexceptions are added as EXDATEs (occurrence removed)modifiedexceptions override start time, duration, room, or metadataaddedexceptions create extra occurrences
const occurrences = recurrence.materialize(weeklyLecture, exceptions, {
start: new Date('2026-03-01'),
end: new Date('2026-03-31'),
});
// Returns ~4 Monday occurrences, minus cancellations, plus modificationsmaterializeSingle
For a non-recurring event, return a single occurrence if it falls within the date range.
materializeSingle(
event: TimetableEvent,
dateRange: DateRange,
): MaterializedOccurrence | nullReturns null if the event does not overlap with the date range.