Calendar Systems: Recurring Events, Time Zones & Free/Busy
Architecture PatternsStore a recurring event as one rule, not thousands of rows; expand it only for the window you are showing; keep times in UTC with the original time zone; compute availability from busy intervals.
A calendar entry that says 'every Monday at 9' is one instruction, not 52 separate sticky notes. You only write the notes for the weeks on screen.
Store the rule. A weekly stand-up for two years would be about 100 rows if you materialise every occurrence, and 'change the time from now on' becomes a risky bulk update. Instead store a recurrence rule in the standard iCalendar form: FREQ=WEEKLY;BYDAY=MO,WE;UNTIL=20271231. Occurrences are computed on demand for the visible range.
Edits to a series. Users change 'just this one', 'this and following' or 'all'. 'Just this one' stores an exception row that overrides one occurrence (or cancels it, an EXDATE). 'This and following' ends the old rule at that date and creates a new rule from there. Keep a stable series id plus the original occurrence time to point exceptions at.
Time zones are the trap. Store the instant in UTC, but also the event's time zone name (America/New_York). 'Every day at 9:00' is 9:00 local time - after a DST change the UTC time shifts by an hour. Expand recurrences in the event's own zone, then convert to UTC, never add 24 hours of UTC to a UTC timestamp.
Query by range. The hot query is 'events between start and end for these calendars'. Index non-recurring events on (calendar_id, start, end). For recurring ones, store the rule's first start and last end (or NULL for forever) so you can quickly skip rules that cannot overlap, then expand the survivors.
Free/busy. Availability is the union of busy intervals: sort by start, merge overlapping intervals, and the gaps are free. Finding a meeting slot for N people means merging everyone's busy lists and scanning for a gap long enough, within working hours, in each person's zone.
Conflicts and double-booking. For rooms and resources a conflict is two bookings with overlapping intervals (start < other_end AND end > other_start). Enforce it in the database (exclusion constraint or a transaction with a lock on the resource), not just in application code, or two simultaneous requests both succeed.
Reminders and invites. Compute the next reminder time and put it in a time-ordered queue or sorted set that workers poll, instead of scanning all events each minute. Invites are fan-out writes to each attendee's calendar; RSVP changes update one row and notify the organiser.
Sync. Clients keep a sync token; the server returns changes since that token. Deleted events become tombstones so offline devices learn about them.
- Store one recurrence rule; expand only the visible range.
- Exceptions override single occurrences; 'this and following' splits the series.
- Keep UTC plus the event's time zone name; expand in local time.
- Free/busy = merge intervals, then read the gaps.
- Enforce no-double-booking in the database, not only in code.
Curated Curation & Deep Insights
ScaleDojo CertifiedOur system architects are vetting high-quality, authorized video guides for Calendar Systems: Recurring Events, Time Zones & Free/Busy with zero third-party platform links.
We are preparing premium, zero-competitor deep-dives for Calendar Systems: Recurring Events, Time Zones & Free/Busy. Authorized reading references will appear automatically.