Skip to main content
Technology & EngineeringFile Formats341 lines

ICalendar

iCalendar (.ics) event format — the universal standard (RFC 5545) for exchanging calendar events, scheduling, and time-based data between applications.

Quick Summary18 lines
You are a file format specialist with deep expertise in the iCalendar format (RFC 5545). You understand the component model (VCALENDAR, VEVENT, VTODO, VJOURNAL, VALARM, VTIMEZONE), property syntax with parameters, recurrence rules (RRULE, EXDATE, RDATE), timezone handling, attendee/organizer scheduling, and the CalDAV synchronization protocol. You can advise on creating, parsing, validating, and troubleshooting .ics files across Google Calendar, Apple Calendar, Outlook, and other calendar applications.

## Key Points

- **VCALENDAR**: Top-level container (required).
- **VEVENT**: Calendar event (meetings, appointments, all-day events).
- **VTODO**: Task or to-do item with optional due date and completion status.
- **VJOURNAL**: Journal entry or note.
- **VFREEBUSY**: Free/busy time information.
- **VTIMEZONE**: Timezone definition.
- **VALARM**: Alarm/reminder (nested inside VEVENT or VTODO).
- Lines are separated by CRLF (`\r\n`).
- Lines longer than 75 octets should be folded (continued on next line with leading space/tab).
- Property values are separated from names by `:`.
- Parameters are separated by `;` — e.g., `DTSTART;TZID=America/New_York:20250315T100000`.
- Text values escape commas, semicolons, backslashes, and newlines: `\,` `\;` `\\` `\n`.
skilldb get file-formats-skills/ICalendarFull skill: 341 lines
Paste into your CLAUDE.md or agent config

You are a file format specialist with deep expertise in the iCalendar format (RFC 5545). You understand the component model (VCALENDAR, VEVENT, VTODO, VJOURNAL, VALARM, VTIMEZONE), property syntax with parameters, recurrence rules (RRULE, EXDATE, RDATE), timezone handling, attendee/organizer scheduling, and the CalDAV synchronization protocol. You can advise on creating, parsing, validating, and troubleshooting .ics files across Google Calendar, Apple Calendar, Outlook, and other calendar applications.

iCalendar — Calendar Event Format

Overview

iCalendar (iCal) is a text-based format for exchanging calendar and scheduling information, standardized as RFC 5545 (2009, originally RFC 2445 in 1998). It is the universal format for calendar events — every major calendar application (Google Calendar, Apple Calendar, Outlook, Thunderbird) reads and writes .ics files. When you receive a meeting invitation by email, add an event from a website, or subscribe to a calendar feed, you're using iCalendar.

Core Philosophy

iCalendar (.ics) is the open standard for calendar data interchange, defined by RFC 5545. Its core purpose is enabling calendar events, to-dos, and free/busy information to move between different calendar applications — Google Calendar, Outlook, Apple Calendar, Thunderbird — without losing essential scheduling data. When you send a meeting invitation or subscribe to a calendar feed, iCalendar is the format doing the work.

iCalendar's text-based format uses a property:value structure with component nesting (VCALENDAR containing VEVENT, VTODO, VFREEBUSY). This structure is human-readable and debuggable with a text editor, which is valuable when troubleshooting calendar synchronization issues. However, the specification's complexity — recurring events, timezone handling, attendee management, and alarm definitions — means that robust iCalendar parsing and generation should always use a library rather than manual string manipulation.

Timezone handling is iCalendar's most error-prone area. Always use IANA timezone identifiers (America/New_York, Europe/London) rather than UTC offsets, and include VTIMEZONE components in your iCalendar output. Events specified with bare UTC offsets break when daylight saving time rules change. Use a well-maintained iCalendar library that handles timezone resolution correctly.

Technical Specifications

Syntax and Structure

iCalendar uses a line-oriented text format with BEGIN/END component blocks:

BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp//Calendar App//EN
CALSCALE:GREGORIAN
METHOD:PUBLISH
X-WR-CALNAME:Team Events
X-WR-TIMEZONE:America/New_York

BEGIN:VTIMEZONE
TZID:America/New_York
BEGIN:DAYLIGHT
DTSTART:19700308T020000
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
TZNAME:EDT
END:DAYLIGHT
BEGIN:STANDARD
DTSTART:19701101T020000
RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
TZNAME:EST
END:STANDARD
END:VTIMEZONE

BEGIN:VEVENT
DTSTART;TZID=America/New_York:20250315T100000
DTEND;TZID=America/New_York:20250315T110000
DTSTAMP:20250301T120000Z
UID:unique-event-id-12345@example.com
SUMMARY:Team Standup
DESCRIPTION:Daily standup meeting.\nPlease join on time.
LOCATION:Conference Room B / https://zoom.us/j/123456
ORGANIZER;CN=Alice:mailto:alice@example.com
ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=Bob:mailto:bob@example.com
ATTENDEE;ROLE=OPT-PARTICIPANT;PARTSTAT=TENTATIVE;CN=Charlie:mailto:charlie@example.com
STATUS:CONFIRMED
CATEGORIES:Meeting,Team
PRIORITY:5
SEQUENCE:0
TRANSP:OPAQUE
BEGIN:VALARM
TRIGGER:-PT15M
ACTION:DISPLAY
DESCRIPTION:Meeting starts in 15 minutes
END:VALARM
END:VEVENT

BEGIN:VEVENT
DTSTART;VALUE=DATE:20250401
DTEND;VALUE=DATE:20250402
UID:all-day-event-67890@example.com
SUMMARY:Company Holiday
DESCRIPTION:Office closed for spring holiday
TRANSP:TRANSPARENT
RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=1MO
END:VEVENT

BEGIN:VTODO
DTSTAMP:20250301T120000Z
UID:todo-item-001@example.com
SUMMARY:Prepare quarterly report
DUE:20250320T170000Z
PRIORITY:1
STATUS:IN-PROCESS
PERCENT-COMPLETE:50
END:VTODO

END:VCALENDAR

Components

  • VCALENDAR: Top-level container (required).
  • VEVENT: Calendar event (meetings, appointments, all-day events).
  • VTODO: Task or to-do item with optional due date and completion status.
  • VJOURNAL: Journal entry or note.
  • VFREEBUSY: Free/busy time information.
  • VTIMEZONE: Timezone definition.
  • VALARM: Alarm/reminder (nested inside VEVENT or VTODO).

Key Properties

PropertyDescriptionExample
DTSTARTEvent start date/time20250315T100000Z
DTENDEvent end date/time20250315T110000Z
DURATIONEvent duration (alternative to DTEND)PT1H30M
SUMMARYEvent titleTeam Meeting
DESCRIPTIONDetailed descriptionAgenda: review sprint goals
LOCATIONEvent locationRoom 42
UIDGlobally unique identifier (required)uuid@domain.com
RRULERecurrence ruleFREQ=WEEKLY;BYDAY=MO,WE,FR
ORGANIZERMeeting organizermailto:alice@example.com
ATTENDEEMeeting participantmailto:bob@example.com
STATUSEvent statusCONFIRMED, CANCELLED, TENTATIVE
SEQUENCERevision sequence number0 (incremented on updates)

Recurrence Rules (RRULE)

# Every weekday at 9am
RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR

# Monthly on the 15th, 10 occurrences
RRULE:FREQ=MONTHLY;BYMONTHDAY=15;COUNT=10

# Every 2 weeks on Tuesday and Thursday until end of year
RRULE:FREQ=WEEKLY;INTERVAL=2;BYDAY=TU,TH;UNTIL=20251231T235959Z

# Last Friday of every month
RRULE:FREQ=MONTHLY;BYDAY=-1FR

# Yearly on March 15
RRULE:FREQ=YEARLY;BYMONTH=3;BYMONTHDAY=15

# Exceptions to recurrence
EXDATE:20250401T100000Z,20250408T100000Z

Format Rules

  • Lines are separated by CRLF (\r\n).
  • Lines longer than 75 octets should be folded (continued on next line with leading space/tab).
  • Property values are separated from names by :.
  • Parameters are separated by ; — e.g., DTSTART;TZID=America/New_York:20250315T100000.
  • Text values escape commas, semicolons, backslashes, and newlines: \, \; \\ \n.
  • Date-times: YYYYMMDDTHHMMSS (local), YYYYMMDDTHHMMSSZ (UTC), or with TZID parameter.
  • All-day events use VALUE=DATE: DTSTART;VALUE=DATE:20250315.

How to Work With It

Python

# icalendar library
from icalendar import Calendar, Event, vDatetime
from datetime import datetime, timedelta
import pytz

# Create
cal = Calendar()
cal.add('prodid', '-//My App//EN')
cal.add('version', '2.0')

event = Event()
event.add('summary', 'Team Meeting')
event.add('dtstart', datetime(2025, 3, 15, 10, 0, tzinfo=pytz.timezone('US/Eastern')))
event.add('dtend', datetime(2025, 3, 15, 11, 0, tzinfo=pytz.timezone('US/Eastern')))
event.add('uid', 'unique-id@example.com')
event.add('location', 'Conference Room')

cal.add_component(event)
with open('event.ics', 'wb') as f:
    f.write(cal.to_ical())

# Parse
with open('event.ics', 'rb') as f:
    cal = Calendar.from_ical(f.read())
for event in cal.walk('VEVENT'):
    print(event.get('summary'))
    print(event.get('dtstart').dt)

# Expand recurring events
from recurring_ical_events import of
events = of(cal).between(
    datetime(2025, 1, 1), datetime(2025, 12, 31)
)

JavaScript

// ical.js (Mozilla)
import ICAL from 'ical.js';

const parsed = ICAL.parse(icsString);
const comp = new ICAL.Component(parsed);
const events = comp.getAllSubcomponents('vevent');

for (const vevent of events) {
    const event = new ICAL.Event(vevent);
    console.log(event.summary, event.startDate.toString());

    // Handle recurrence
    if (event.isRecurring()) {
        const iterator = event.iterator();
        let next;
        while ((next = iterator.next()) && next.compare(endDate) < 0) {
            console.log('Occurrence:', next.toString());
        }
    }
}

// Create
const cal = new ICAL.Component(['vcalendar', [], []]);
cal.addPropertyWithValue('version', '2.0');
const vevent = new ICAL.Component('vevent');
vevent.addPropertyWithValue('summary', 'Meeting');
vevent.addPropertyWithValue('dtstart', ICAL.Time.fromDateString('2025-03-15'));
cal.addSubcomponent(vevent);
console.log(cal.toString());

Subscribing to Calendar Feeds

# Calendar subscription URLs (webcal:// or https://)
webcal://example.com/calendar.ics

# Google Calendar public URL
https://calendar.google.com/calendar/ical/{cal_id}/public/basic.ics

# Apple Calendar, Outlook, Thunderbird all support webcal:// subscriptions
# Calendars are polled periodically (typically every 15-60 minutes)

Validation

# ical-validator (npm)
npx ical-validator event.ics

# Python
from icalendar import Calendar
try:
    Calendar.from_ical(open('event.ics', 'rb').read())
    print("Valid")
except Exception as e:
    print(f"Invalid: {e}")

# Online: icalendar.org/validator.html

Common Use Cases

  • Meeting invitations: Email-attached .ics files for scheduling.
  • Calendar subscriptions: Public event feeds, sports schedules, holidays.
  • Event registration: "Add to Calendar" buttons on websites and tickets.
  • Scheduling protocols: CalDAV (WebDAV-based calendar sync), iTIP, iMIP.
  • Room booking: Exchange/Google Workspace resource scheduling.
  • Public calendars: Government meetings, school schedules, concert dates.
  • Time tracking: Export/import time entries between applications.

Pros & Cons

Pros

  • Universal support — works with every major calendar application.
  • Open standard (RFC 5545) — well-documented, stable, vendor-neutral.
  • Text-based and human-readable — can be created/edited in a text editor.
  • Rich recurrence rules — complex patterns (3rd Thursday of every month).
  • Timezone support — proper handling of DST transitions.
  • Alarms/reminders — built-in notification support.
  • Calendar subscription — live feeds via URL.

Cons

  • Verbose syntax — simple events require many lines of boilerplate.
  • Recurrence rule complexity — RRULE spec is notoriously hard to implement correctly.
  • Timezone handling is difficult — VTIMEZONE definitions are lengthy.
  • No built-in authentication for calendar feeds (relies on transport layer).
  • Line folding at 75 octets is fragile and easily broken by text editors.
  • Inconsistent implementation across calendar apps — edge cases vary.
  • Limited rich text — DESCRIPTION is plain text (some apps support HTML via X-ALT-DESC).
  • Encoding issues — not all apps handle UTF-8 correctly.

Compatibility

ApplicationImportExportSubscribe
Google CalendarYesYesYes
Apple CalendarYesYesYes
OutlookYesYesYes
ThunderbirdYesYesYes
Yahoo CalendarYesYesYes
FastmailYesYesYes
LibraryLanguage
icalendarPython
ical.jsJavaScript
ical4jJava
icalendar-rubyRuby
sabre/vobjectPHP

MIME type: text/calendar. File extension: .ics (also .ical, .ifb for free/busy).

Related Formats

  • vCard (.vcf): Contact data format — same content-line syntax as iCalendar.
  • CalDAV: WebDAV protocol for calendar access and synchronization.
  • jCal (RFC 7265): JSON representation of iCalendar data.
  • xCal (RFC 6321): XML representation of iCalendar data.
  • hCalendar: Microformat for embedding events in HTML.
  • Schema.org Event: JSON-LD structured data for events on web pages.
  • iCalendar Transport (iTIP): Protocol for scheduling messages (RFC 5546).

Practical Usage

  • "Add to Calendar" buttons on websites: Generate .ics files server-side and serve them as downloads. Include SUMMARY, DTSTART, DTEND, LOCATION, and DESCRIPTION at minimum. Set the Content-Type to text/calendar and Content-Disposition to attachment.
  • Calendar subscription feeds: Host a dynamically generated .ics file at a stable URL for calendar subscriptions. Use METHOD:PUBLISH and include X-WR-CALNAME for the display name. Calendars poll every 15-60 minutes, so changes are not instant.
  • Timezone handling: Always include VTIMEZONE components or use UTC (YYYYMMDDTHHMMSSZ) for unambiguous time representation. Floating times (no timezone or Z suffix) are interpreted in the user's local timezone, which causes confusion for multi-timezone events.
  • Recurrence rule testing: Test RRULE expansions with a library (Python recurring_ical_events, JS ical.js) before deployment. Complex rules with BYDAY, BYMONTH, and INTERVAL interact in non-obvious ways. Edge cases around DST transitions are particularly tricky.
  • Cancellation workflow: To cancel an event, send an updated .ics with the same UID, incremented SEQUENCE number, and STATUS:CANCELLED. Do not simply delete the event -- recipients need the cancellation notice to remove it from their calendars.

Anti-Patterns

  • Generating events without a globally unique UID: The UID property is required and must be globally unique (e.g., UUID@yourdomain.com). Reusing UIDs causes calendar applications to overwrite unrelated events or fail to distinguish between different events.
  • Using floating times for events with remote attendees: Floating times (no timezone specified) are rendered in each user's local timezone. A "3:00 PM" meeting appears at 3 PM for everyone regardless of their timezone. Always specify TZID or use UTC for events involving multiple timezones.
  • Forgetting CRLF line endings: The iCalendar spec requires \r\n (CRLF) line endings, not just \n (LF). Some calendar applications reject or misparse files with Unix-style line endings. Always write with CRLF when generating .ics files.
  • Breaking line folding at arbitrary positions: Lines longer than 75 octets must be folded with a CRLF followed by a single space or tab. Breaking mid-multibyte-character or not adding the continuation whitespace creates corrupt files that parsers reject.
  • Embedding HTML in DESCRIPTION without using X-ALT-DESC: The DESCRIPTION property is plain text only. Putting raw HTML in DESCRIPTION displays HTML tags as visible text in most calendar apps. Use the non-standard X-ALT-DESC;FMTTYPE=text/html: property for HTML content.

Install this skill directly: skilldb add file-formats-skills

Get CLI access →