Taming Time: How to Handle Recurring Events in Calendar Code
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:
- Why recurring events are hard
- Approaches to modeling them
- How to generate future occurrences
- Dealing with exceptions, edits, and deletions
- Libraries and tools that can help
Why Recurring Events Are Hard
Calendar events fall into two basic categories:
- One-time events: A meeting on June 20th at 10am
- Recurring events: A yoga class every Wednesday at 6pm
But "recurring" can mean:
- Every weekday
- The 1st Monday of each month
- Every 2 weeks on Tuesday and Thursday
- Every December 25th, forever
Now add complexity:
- Time zone changes (e.g., daylight saving time)
- Leap years
- Skipped dates (e.g., holidays)
- Edits to a single instance or the whole series
- Deletion of just one event or all future ones
This is why naive implementations—like storing a bunch of duplicate events—tend to fall apart fast.
Data Modeling: How Should You Store Recurring Events?
Approach 1: Rule + Start/End Date
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.
Approach 2: Store Rule and Generate Instances Dynamically
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.
Generating Recurrence Instances
To generate future events, you'll need:
- A recurrence rule parser
- A start date
- A date range for expansion (e.g., "show all events this month")
In Python
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))
In JavaScript
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)
Handling Exceptions
Let’s say a client cancels just one upcoming instance—do you:
- Delete it from a generated list?
- Add an "exception" object?
Recommended Strategy:
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:
- Skip any dates in the
exceptions
list - Replace with any overrides that exist
Editing a Series
Users typically want to:
- Edit just one instance
- Edit all future events
- Edit the entire series
The best practice is to:
- Store a parent event ID
- On "edit future events", split the series at a given date and create a new rule starting from that point
- On "edit this instance", create an override
Performance Considerations
If you're displaying a calendar UI that shows 30–90 days of data:
- Generate only events within that window
- Avoid precomputing all future occurrences—some rules go infinitely!
Index and cache expanded events if needed for performance in mobile or embedded contexts.
Libraries Worth Knowing
- Python:
dateutil.rrule
,ics.py
,arrow
- JavaScript:
rrule.js
,luxon
,day.js
- Java/Kotlin:
ical4j
,Joda-Time
- iOS (Swift):
SwiftRRule
,EventKit
- Database layer: Consider keeping the recurrence rule in your backend and expanding as-needed in API calls
Final Thoughts
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:
- Use standard RRULEs
- Store base rules and generate on demand
- Handle exceptions and overrides cleanly
- Design your UI/UX around recurrence logic (especially for editing)
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.