Taming Time: How to Handle Recurring Events in Calendar Code
Whether you're building a field service software scheduling feature, a personal calendar app,
Whether you're building a field service software scheduling feature, a personal calendar app, or a workplace booking tool, recurring events are one of the trickiest features to get right. On the surface, “every Monday at 9am” sounds simple. But once you dive in, you’ll uncover a time-twisting labyrinth of edge cases, time zones, exceptions, and calendar quirks.
In this post, we’ll break down:
Calendar events fall into two basic categories:
But "recurring" can mean:
Now add complexity:
This is why naive implementations—like storing a bunch of duplicate events—tend to fall apart fast.
jsonCopyEdit{
"title": "Weekly Staff Meeting",
"start": "2025-06-17T09:00:00Z",
"recurrenceRule": "FREQ=WEEKLY;BYDAY=TU",
"end": null
}
Most robust calendar systems follow RFC 5545, the iCalendar recurrence rule format (RRULE
). It's supported by standards like Google Calendar and Outlook.
You store the series rule once, and generate the actual event instances on demand (e.g., for a UI calendar view or export). This avoids bloating your database with hundreds of copies.
To generate future events, you'll need:
Use dateutil.rrule
:
pythonCopyEditfrom dateutil.rrule import
rrulestrrule = rrulestr("FREQ=WEEKLY;BYDAY=TU", dtstart=datetime(2025, 6, 17, 9, 0
))instances = list
(rule.between(start, end))
Use rrule.js
:
jsCopyEditconst { RRule } = require('rrule'
)const rule = new RRule
({ freq: RRule.WEEKLY
, byweekday: [RRule.TU
], dtstart: new Date(Date.UTC(2025, 5, 17, 9, 0
))
})const occurrences = rule.between
(startDate, endDate)
Let’s say a client cancels just one upcoming instance—do you:
Store a list of exceptions and overrides:
jsonCopyEdit{
"exceptions": ["2025-07-01T09:00:00Z"],
"overrides": {
"2025-07-08T09:00:00Z": {
"title": "Moved Staff Meeting",
"start": "2025-07-08T10:00:00Z"
}
}
}
Then, when generating events, you:
exceptions
listUsers typically want to:
The best practice is to:
If you're displaying a calendar UI that shows 30–90 days of data:
Index and cache expanded events if needed for performance in mobile or embedded contexts.
dateutil.rrule
, ics.py
, arrow
rrule.js
, luxon
, day.js
ical4j
, Joda-Time
SwiftRRule
, EventKit
Recurring events are deceptively complex. But with the right model and tooling, you can avoid a spaghetti mess of duplicate rows and edge-case bugs.
Always:
The best calendar system for lawn maintenance companies make this feel simple for the user—because they hide all the complexity underneath.
Read this, if you're looking for info on creating calendar software with React.