System Design: Design Google Calendar — Scheduling, Recurring Events, Reminders, Timezone, Free/Busy, Room Booking

Google Calendar manages billions of events for hundreds of millions of users with complex scheduling requirements: recurring events with exceptions, timezone handling across global teams, free/busy availability computation, and meeting room booking. This guide covers the calendar-specific challenges that go beyond the basics covered in our Calendar System overview — focusing on the hard problems that make calendar design a senior-level interview question.

Recurring Event Edge Cases

Recurring events with RFC 5545 RRULE are conceptually simple but operationally complex. Edge cases: (1) “This and following events” edit — user modifies one instance of a recurring series and selects “this and following events.” This splits the original RRULE into two: the original rule with an UNTIL date (ending at the split point) and a new rule starting from the split point with the modifications. Both rules must maintain their own exception lists (EXDATE). (2) Timezone changes — a recurring event at “9 AM America/New_York” must correctly handle DST transitions. During EST: 9 AM = 14:00 UTC. During EDT: 9 AM = 13:00 UTC. If you store the recurrence in UTC (14:00 UTC daily), the event shifts to 10 AM during summer. Solution: always expand the RRULE in the original timezone, then convert each instance to UTC. (3) Last day of month — “monthly on the 31st” skips February (28/29 days), April (30 days), etc. RFC 5545 handles this by skipping months without the specified day. Some implementations use “last day of month” instead. (4) Moving holidays — “first Monday of September” (Labor Day). RRULE: FREQ=YEARLY;BYDAY=1MO;BYMONTH=9. The library must correctly compute the first Monday each year.

Free/Busy and Group Scheduling

Free/busy computation: given a user and a time range, compute which times are free and which are busy. Algorithm: (1) Fetch all events (including expanded recurring instances) in the time range. (2) Merge overlapping busy intervals into a consolidated timeline. (3) Free slots = time range minus busy intervals. (4) Apply working hours (only show availability 9 AM – 6 PM in the user timezone). Optimization: pre-compute and cache the free/busy timeline per user per day. Invalidate when any event in that day changes. The FreeBusy API (CalDAV standard) returns busy intervals without exposing event details — preserving privacy while enabling scheduling. Group scheduling (“find a time” for 8 attendees): compute the intersection of all attendees free slots. With 8 people, the intersection may be empty for the requested duration. Strategies: (1) Show “best available” times ranked by number of available attendees. (2) Suggest times when the fewest “required” attendees are busy (optional attendees weighted lower). (3) Allow the organizer to override and book despite conflicts. Smart scheduling: an ML model predicts optimal meeting times based on: attendee working hour patterns (some people are morning people), historical meeting acceptance rates by time, and buffer preferences (avoid back-to-back meetings for attendees with many meetings).

Meeting Room Booking

Enterprise calendar systems manage meeting room resources alongside user calendars. A room is a calendar with its own events (bookings) and free/busy status. Booking flow: the organizer adds a room to the meeting invitation. The system checks the room free/busy. If available: the room is booked (an event is added to the room calendar). If unavailable: suggest alternative rooms that are available for the requested time. Room selection algorithm: from available rooms, rank by: capacity match (do not book a 20-person room for a 3-person meeting — waste), floor/building proximity (prefer rooms near the attendees offices), equipment match (the meeting requires a video conferencing setup), and historical preference (the team usually books this room). Preventing double-booking: the room booking must be atomic. Two organizers booking the same room at the same time: use a database constraint or SELECT FOR UPDATE on the room calendar. Only one booking succeeds. The other receives a “room no longer available” error and must select a different room. Auto-release: if no one checks in to the room within 10 minutes of the meeting start (detected by room sensors, Bluetooth beacons, or manual check-in), the booking is auto-released and the room becomes available. This prevents “ghost bookings” that waste room capacity.

Calendar Sync and Interoperability

Users have calendars on multiple platforms (Google Calendar, Outlook, Apple Calendar). Sync protocols: CalDAV (RFC 4791) — the standard for calendar sync. The client sends a REPORT request with a sync-token. The server returns all changes since that token: new events, modified events, deleted events. The client applies changes and stores the new token. Incremental sync avoids downloading the entire calendar. iCalendar (.ics) — the standard event format. VEVENT components contain: DTSTART, DTEND, RRULE, SUMMARY, LOCATION, ATTENDEE, and ORGANIZER. .ics files are exchanged as email attachments for meeting invitations. Exchange ActiveSync — Microsoft protocol for Exchange/Outlook sync. Proprietary but widely supported. Google Calendar API — REST API for programmatic access. OAuth2 authentication. Supports: event CRUD, free/busy queries, calendar list management, and push notifications (via webhooks when events change). Cross-platform meeting invitations: the organizer sends an email with an .ics attachment. The recipient calendar app parses the .ics and adds the event. RSVP responses update the organizer event (accept/decline/tentative). This works across Google Calendar, Outlook, and Apple Calendar because they all support the iCalendar standard.

Reminders and Notifications

Each event can have one or more reminders: 10 minutes before, 1 hour before, 1 day before. Reminder types: push notification (mobile), email, and desktop notification (browser). Scheduling reminders: a cron-like scheduler checks for events with reminders due in the next minute. For each: compute the reminder time (event_start – reminder_offset), check if the current time matches, and enqueue a notification job. Scale: with 1 billion events per day and an average of 1.5 reminders per event: 1.5 billion reminder checks per day = 17,000 per second. The scheduler must be efficient: index events by (reminder_time) so the query is a range scan, not a full table scan. Alternatively: when an event is created, pre-schedule the reminder as a delayed job (Redis sorted set with score = reminder_timestamp). The scheduler pops due reminders from the sorted set. This is more efficient than scanning all events. Snooze: when a notification fires, the user can snooze (reschedule for 5 minutes later). Create a new delayed job for the snoozed time. Default reminders: users set default reminder preferences (e.g., 10 minutes for meetings, 1 day for all-day events). New events inherit these defaults unless overridden.

{“@context”:”https://schema.org”,”@type”:”FAQPage”,”mainEntity”:[{“@type”:”Question”,”name”:”How does Google Calendar prevent double-booking of meeting rooms?”,”acceptedAnswer”:{“@type”:”Answer”,”text”:”Room booking must be atomic: two organizers booking the same room at the same time must result in only one success. Implementation: database transaction with SELECT FOR UPDATE on the room calendar for the requested time range. If no conflicting booking exists: INSERT the room booking. The lock prevents concurrent bookings. The second organizer receives room no longer available and must select an alternative. Room selection algorithm ranks available rooms by: capacity match (avoid wasting a 20-person room for 3 people), floor proximity to attendees, equipment match (video conferencing needed?), and historical preference. Auto-release: if no one checks in within 10 minutes (room sensors or manual check-in), the booking is released for others. This prevents ghost bookings that waste capacity.”}},{“@type”:”Question”,”name”:”How are recurring event edge cases handled in a calendar system?”,”acceptedAnswer”:{“@type”:”Answer”,”text”:”Edge cases that break naive implementations: (1) This and following events edit: splits the RRULE into two separate rules at the edit point. Each maintains independent exception lists. (2) DST transitions: a 9 AM America/New_York event must expand the RRULE in the original timezone (not UTC) to correctly handle EST->EDT transitions. Storing as 14:00 UTC daily would shift to 10 AM during summer. (3) Last day of month: monthly on the 31st skips months with fewer days. RFC 5545 handles this by omitting instances in short months. (4) Moving holidays: first Monday of September requires correct first-weekday-of-month computation each year. Always use a standards-compliant RRULE library (python-dateutil, iCal4j) rather than implementing expansion manually.”}}]}
Scroll to Top