“Design Google Calendar mobile” is a deceptively simple-sounding question. Until the interviewer asks: how do you handle a daylight-saving boundary in a recurring event? How do you reconcile when two devices edited the same event offline? What is the right way to show a meeting that crosses midnight in two time zones?
Functional requirements
- View calendar by day, week, month
- Create, edit, delete events
- Recurring events (daily, weekly, monthly, custom)
- Multi-calendar support (work, personal, shared)
- Time zone awareness
- Reminders and notifications
- Offline event creation
Architecture
Local SQLite as source of truth for offline use, sync engine for two-way reconciliation, notification scheduler for reminders.
Event model
An event has:
- Server ID (assigned on first sync)
- Local UUID (for offline creation)
- Start, end, time zone, all-day flag
- RRULE (recurrence rule, RFC 5545)
- EXDATE (excluded dates)
- Recurrence-ID (for modifications to specific instances)
- Updated-at, sequence number
Recurrence
RFC 5545 RRULE is the standard. Examples: RRULE:FREQ=WEEKLY;BYDAY=MO,WE,FR;UNTIL=20260901.
To render a calendar, expand the recurrence into instances within the visible window. Cache the expansion. Recompute on edit.
Modifying a single instance creates an “exception” event with the same Recurrence-ID. The original series continues unchanged.
Time zones
Always store events in UTC + IANA time zone identifier (e.g., “America/New_York”). Render in the user’s local time zone, but for events explicitly in another zone (e.g., a flight from JFK), render in the event’s zone.
Daylight saving transitions can shift recurring events by an hour. Be deliberate: usually preserve “8am every weekday in NYC time” rather than “13:00 UTC.”
Sync
iCalendar / Google Calendar API. Each event has a sequence number and an updated-at. On sync conflict (same event modified on two devices), the higher sequence wins.
For deletes: tombstones with TTL. Allows offline devices to learn about deletions when they reconnect.
Reminders
Local notification scheduling. iOS: UNUserNotificationCenter with up to 64 pending notifications. Android: AlarmManager with exact alarm permission.
For events with email/SMS reminders, the server is responsible — mobile only handles local push.
Offline event creation
Events created offline have a local UUID. On sync, the server assigns a real ID and the client maps the UUID to the new ID. References (e.g., a recurring exception) are remapped.
Battery and data
- Sync only when foreground or push-triggered
- Calendar widgets refresh every 15–30 minutes max
- Recurrence expansion is cached, not re-computed every render
Frequently Asked Questions
How do you handle the meeting-crosses-midnight case?
Render the event spanning two days. The cell renderer needs to be aware that an event can occupy parts of multiple day boxes.
What if two devices edit the same event offline?
Last-writer-wins by sequence number. Show the user a UI cue if their write was overridden.
How do you handle a 100-year recurring event?
Expand only within the visible window (typically 1 month). Lazy-expand on demand. Never materialize all 36,500 instances.