Recurrence
Recurrence is where calendar plugins live or die. Owl implements RFC 5545 recurrence rules with a framework-agnostic, thoroughly unit-tested engine — and it’s included free in Lite, not paywalled.
Recurrence rules
An event can repeat daily, weekly, monthly or yearly, with an interval and either an end date or a count. Examples:
- Every week on Friday, 12 times.
- Every 2 weeks on Tuesday and Thursday.
- The first Monday of every month.
- Every year on June 21.
Owl stores the canonical RRULE and expands it in the event’s timezone, storing each instant in UTC.
Materialised occurrences
Rather than expanding rules at query time, Owl writes each occurrence to an indexed table. A queue job generates occurrences out to a rolling horizon (a couple of years by default, configurable in settings), and tops the horizon up over time so far-future dates keep appearing. This makes range queries and pagination fast, plain SQL.
Run the queue in production (php craft queue/run or a daemon) so occurrence generation and horizon top-ups happen promptly. A scheduled task keeps the horizon rolling forward.
Exceptions
Remove a single date from a series with an exception (EXDATE) — for example, skip the event that falls on a public holiday. The occurrence simply isn’t generated for that date.
Single-occurrence overrides
Sometimes one instance differs from the rest: a different start time, a different title, or a one-off cancellation. Owl supports per-occurrence overrides that change a single occurrence without affecting the rest of the series.
Daylight saving time
Because Owl expands recurrence in the event’s IANA timezone, daylight-saving transitions are handled correctly. A 9:00 am weekly event stays at 9:00 am local time across both spring-forward and fall-back — this is explicitly tested against real DST dates, including the “skipped” and “repeated” wall-clock hours.