Skip to main content
Give an event a recurrence rule and Calendar expands it into concrete occurrences automatically: over the visible range in the month, week, day, 3days, and custom modes, and over a rolling three-month window in schedule (the agenda has no bounded viewport of its own). Non-recurring events pass through untouched, so you can mix both freely.
When you want the occurrences yourself (to save, export to iCal, or list them over a window of your own), expand them with expandRecurringEvents and pass the result as events:
Rules support:
  • freq"daily", "weekly", "monthly", or "yearly".
  • interval — every N periods (e.g. every 2 weeks).
  • count — stop after N occurrences.
  • until — stop on or before a date.
  • weekdays — which days, for weekly rules (0 = Sunday).
  • nthWeekday — for monthly/yearly, repeat on the Nth weekday instead of the day-of-month, e.g. { week: 3, weekday: 1 } (the 3rd Monday) or { week: -1, weekday: 5 } (the last Friday).
  • monthDays — for monthly, the day(s) of the month to repeat on, e.g. [1, 15] (the 1st and 15th) or [-1] (the last day; negatives count from the month’s end). Days a month lacks (the 31st in February) are skipped.
  • months — for yearly, the month(s) to repeat in (1 = January … 12 = December), keeping the start date’s day-of-month, e.g. [3, 9] (every March and September).
  • exdates — dates to skip (exceptions). A date at local midnight skips every occurrence on that calendar day; a date with a time skips only the occurrence starting at that exact instant, so two same-day occurrences can be cancelled independently.
  • rdates — extra one-off dates added to the set, even ones the rule wouldn’t produce.
Each occurrence keeps the original duration and fields; non-recurring events pass through unchanged. These rules map to and from iCal RRULE/BYMONTHDAY/BYMONTH/EXDATE/RDATE — see iCalendar.
Compute the range from the visible window. onChangeDateRange gives you the [start, end] of what’s on screen each time the user pages — a good trigger to re-expand (and to fetch from a server).
Expansion fast-forwards to the range you ask for, so a long-lived rule (a daily event started years ago) stays cheap to query far in the future. A single expandRecurringEvents call emits at most 5000 occurrences within the range; pass a count/until, or query a tighter window, if you need more.