ICS File Format Explained: Structure, Syntax & Examples
What the ICS file format is and how it's built — required fields, time zones, RRULE, and validation, with copy-paste examples.
January 22, 2026
8 min read
The ICS file format (iCalendar) is the universal standard for calendar data exchange. Whether you're building calendar features into an app, troubleshooting import errors, or just curious how calendar files work, this technical guide explains the complete ICS file structure with examples.
What is an ICS File?
ICS (Internet Calendaring and Scheduling) is a text-based file format defined by RFC 5545. It's the standard used by all major calendar applications:
- Google Calendar
- Apple Calendar
- Microsoft Outlook
- Mozilla Thunderbird
- And virtually every other calendar app
File extensions: .ics, .ical, .ifb (for free/busy info)
MIME type: text/calendar
Basic ICS File Structure
Every ICS file follows this basic structure:
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Your Organization//Your Product//EN
[Calendar Properties]
BEGIN:VEVENT
[Event Properties]
END:VEVENT
BEGIN:VEVENT
[Event Properties]
END:VEVENT
END:VCALENDAR
Key concepts:
- VCALENDAR: Top-level container (required)
- VEVENT: Individual calendar event (can have multiple)
- Properties: Key-value pairs defining event details
- Components: Structured sections (VEVENT, VTODO, VJOURNAL, etc.)
Minimal Valid ICS File
The absolute minimum for a valid ICS file:
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp//Example Calendar//EN
BEGIN:VEVENT
UID:12345@example.com
DTSTAMP:20260122T120000Z
DTSTART:20260125T140000Z
SUMMARY:Team Meeting
END:VEVENT
END:VCALENDAR
Required VCALENDAR properties:
VERSION: iCalendar version (always2.0)PRODID: Product identifier (format:-//Organization//Product//Language)
Required VEVENT properties:
UID: Unique identifier for the eventDTSTAMP: Timestamp when the event was createdDTSTART: Event start date/time
Required structure:
BEGIN:VCALENDARandEND:VCALENDARBEGIN:VEVENTandEND:VEVENT
Common VEVENT Properties
Event Identification
UID (Unique Identifier)
UID:20260122T120000Z-12345@example.com
- Required
- Must be globally unique
- Format: Any string, often
timestamp-random@domain.com - Used to identify the same event across updates
DTSTAMP (Date-Time Stamp)
DTSTAMP:20260122T120000Z
- Required
- Creation or last modification timestamp
- Format: UTC time with
Zsuffix - Format:
YYYYMMDDTHHMMSSidZ
Event Timing
DTSTART (Start Date/Time)
DTSTART:20260125T140000Z
- Required
- Event start date and time
- Can be UTC (
Zsuffix) or local time with time zone
With time zone:
DTSTART;TZID=America/New_York:20260125T140000
All-day event:
DTSTART;VALUE=DATE:20260125
DTEND (End Date/Time)
DTEND:20260125T150000Z
- Event end date and time
- Optional (if omitted, assumes instant event or all-day)
- Format same as DTSTART
DURATION (Alternative to DTEND)
DTSTART:20260125T140000Z
DURATION:PT1H
- Alternative to DTEND
- Format: ISO 8601 duration (
PT1H= 1 hour,PT30M= 30 minutes,P1D= 1 day)
Event Content
SUMMARY (Title)
SUMMARY:Team Meeting
- Event title (shows in calendar apps)
- Optional but recommended
- Plain text
DESCRIPTION (Details)
DESCRIPTION:Discuss Q1 goals and assign action items.
- Event notes or details
- Supports multiple lines (use
\nfor line breaks)
LOCATION (Where)
LOCATION:Conference Room A\, Building 1
- Event location
- Escape commas with backslash (
\,)
Event Metadata
STATUS
STATUS:CONFIRMED
- Event status
- Values:
TENTATIVE,CONFIRMED,CANCELLED
CLASS
CLASS:PUBLIC
- Privacy level
- Values:
PUBLIC,PRIVATE,CONFIDENTIAL
TRANSP (Transparency)
TRANSP:OPAQUE
- Show as busy or free
- Values:
OPAQUE(busy),TRANSPARENT(free)
Time Zones in ICS Files
Time zones are one of the most complex parts of ICS files.
Option 1: Use UTC Time
Simplest approach—all times in UTC with Z suffix:
DTSTART:20260125T190000Z
DTEND:20260125T200000Z
Z= UTC (Coordinated Universal Time)- No time zone conversion needed
- Calendar apps convert to user's local time automatically
Option 2: Use TZID (Time Zone Identifier)
Explicitly specify the time zone:
DTSTART;TZID=America/New_York:20260125T140000
DTEND;TZID=America/New_York:20260125T150000
TZIDuses IANA time zone database names- Event stays locked to that time zone
- Handles daylight saving time automatically
Common TZID values:
America/New_York(Eastern US)America/Chicago(Central US)America/Los_Angeles(Pacific US)Europe/London(UK)Europe/Paris(Central Europe)Asia/Tokyo(Japan)Australia/Sydney(Australia)
Full list: IANA Time Zone Database
Option 3: Include VTIMEZONE Component
For maximum compatibility, include full time zone definitions:
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example//Calendar//EN
BEGIN:VTIMEZONE
TZID:America/New_York
BEGIN:STANDARD
DTSTART:20251102T020000
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
END:STANDARD
BEGIN:DAYLIGHT
DTSTART:20260308T020000
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
END:DAYLIGHT
END:VTIMEZONE
BEGIN:VEVENT
UID:123@example.com
DTSTAMP:20260122T120000Z
DTSTART;TZID=America/New_York:20260125T140000
DTEND;TZID=America/New_York:20260125T150000
SUMMARY:Team Meeting
END:VEVENT
END:VCALENDAR
When to include VTIMEZONE:
- For maximum compatibility with older calendar apps
- When sharing calendars across different systems
- When targeting specific time zone rules
When to skip VTIMEZONE:
- Most modern apps (Google Calendar, Apple Calendar, Outlook) don't need it
- Using UTC time (no time zone needed)
- Simplifying file size
Recurring Events (RRULE)
Recurring events use the RRULE property.
Basic Recurring Patterns
Daily:
RRULE:FREQ=DAILY
Weekly:
RRULE:FREQ=WEEKLY
Monthly:
RRULE:FREQ=MONTHLY
Yearly:
RRULE:FREQ=YEARLY
Recurring with Limits
Count (ends after X occurrences):
RRULE:FREQ=WEEKLY;COUNT=10
- Recurs weekly for 10 occurrences, then stops
Until (ends on specific date):
RRULE:FREQ=DAILY;UNTIL=20260201T235959Z
- Recurs daily until Feb 1, 2026
Advanced Recurring Patterns
Every weekday (Monday-Friday):
RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR
Every Monday and Wednesday:
RRULE:FREQ=WEEKLY;BYDAY=MO,WE
First Monday of every month:
RRULE:FREQ=MONTHLY;BYDAY=1MO
Last Friday of every month:
RRULE:FREQ=MONTHLY;BYDAY=-1FR
Every 2 weeks:
RRULE:FREQ=WEEKLY;INTERVAL=2
Every 3 months:
RRULE:FREQ=MONTHLY;INTERVAL=3
Complete Recurring Event Example
BEGIN:VEVENT
UID:recurring-123@example.com
DTSTAMP:20260122T120000Z
DTSTART;TZID=America/New_York:20260126T090000
DTEND;TZID=America/New_York:20260126T093000
RRULE:FREQ=WEEKLY;BYDAY=MO,WE,FR;COUNT=20
SUMMARY:Morning Standup
DESCRIPTION:Daily team sync
LOCATION:Zoom
END:VEVENT
- Recurs every Monday, Wednesday, Friday at 9am Eastern
- For 20 occurrences
- 30-minute duration
See our RRULE Generator for creating complex patterns.
Advanced Properties
Attendees
ATTENDEE;CN="John Doe";ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:john@example.com
ATTENDEE;CN="Jane Smith";ROLE=OPT-PARTICIPANT;RSVP=FALSE:mailto:jane@example.com
CN: Common name (display name)ROLE:REQ-PARTICIPANT(required),OPT-PARTICIPANT(optional),CHAIR(organizer)RSVP:TRUE(response requested),FALSE(no response needed)
Organizer
ORGANIZER;CN="Meeting Coordinator":mailto:coordinator@example.com
- Person who created/manages the event
Alarms/Reminders
BEGIN:VALARM
TRIGGER:-PT15M
ACTION:DISPLAY
DESCRIPTION:Reminder: Team Meeting in 15 minutes
END:VALARM
TRIGGER: When to trigger (-PT15M= 15 minutes before)ACTION:DISPLAY(notification),AUDIO(sound),EMAIL(email reminder)
Attachments
ATTACH:https://example.com/meeting-agenda.pdf
- URL to attached file
Categories/Tags
CATEGORIES:Work,Important,Q1
- Comma-separated tags
Line Folding and Escaping
ICS files have strict formatting rules.
Line Folding
Lines must not exceed 75 octets. Longer lines are "folded":
DESCRIPTION:This is a very long description that exceeds 75 characters and
must be wrapped to the next line with a leading space.
- Continuation lines start with a single space or tab
Escaping Special Characters
Commas, semicolons, backslashes:
SUMMARY:Meeting\, discussion\; action items
LOCATION:Building A\, Room 101
- Escape with backslash (
\)
Line breaks:
DESCRIPTION:Line 1\nLine 2\nLine 3
- Use
\nfor newlines
Quotes (not needed):
SUMMARY:Event Title
- Do NOT wrap values in quotes (unless the quote is part of the text)
Multiple Events in One ICS File
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example//Calendar//EN
BEGIN:VEVENT
UID:event1@example.com
DTSTAMP:20260122T120000Z
DTSTART:20260125T140000Z
SUMMARY:Event 1
END:VEVENT
BEGIN:VEVENT
UID:event2@example.com
DTSTAMP:20260122T120000Z
DTSTART:20260126T100000Z
SUMMARY:Event 2
END:VEVENT
BEGIN:VEVENT
UID:event3@example.com
DTSTAMP:20260122T120000Z
DTSTART:20260127T150000Z
SUMMARY:Event 3
END:VEVENT
END:VCALENDAR
- Single
VCALENDARwrapper - Multiple
VEVENTcomponents - Each event has unique UID
Common ICS File Errors
Missing Required Fields
Error:
BEGIN:VEVENT
DTSTART:20260125T140000Z
SUMMARY:Meeting
END:VEVENT
Problem: Missing UID and DTSTAMP
Fix:
BEGIN:VEVENT
UID:12345@example.com
DTSTAMP:20260122T120000Z
DTSTART:20260125T140000Z
SUMMARY:Meeting
END:VEVENT
Mismatched BEGIN/END Tags
Error:
BEGIN:VEVENT
SUMMARY:Meeting
END:VCALENDAR
Problem: Started with BEGIN:VEVENT but ended with END:VCALENDAR
Fix: Every BEGIN:X must have matching END:X
Invalid Date/Time Format
Error:
DTSTART:2026-01-25 14:00:00
Problem: Wrong format (includes dashes and spaces)
Fix:
DTSTART:20260125T140000Z
- Format:
YYYYMMDDTHHMMSSidZ(no dashes, no spaces)
Missing VCALENDAR Wrapper
Error:
BEGIN:VEVENT
UID:123@example.com
DTSTAMP:20260122T120000Z
DTSTART:20260125T140000Z
SUMMARY:Meeting
END:VEVENT
Problem: No VCALENDAR container
Fix:
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example//Calendar//EN
BEGIN:VEVENT
UID:123@example.com
DTSTAMP:20260122T120000Z
DTSTART:20260125T140000Z
SUMMARY:Meeting
END:VEVENT
END:VCALENDAR
Validating ICS Files
Use an ICS Validator to check for errors:
- Missing required fields
- Syntax errors
- Invalid date/time formats
- Mismatched BEGIN/END tags
- Line length violations
Related troubleshooting guides:
Creating ICS Files Programmatically
Example: Python
from datetime import datetime
def create_ics(title, start, end, location="", description=""):
uid = f"{datetime.now().timestamp()}@example.com"
dtstamp = datetime.utcnow().strftime("%Y%m%dT%H%M%SZ")
dtstart = start.strftime("%Y%m%dT%H%M%SZ")
dtend = end.strftime("%Y%m%dT%H%M%SZ")
ics = f"""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example//Calendar//EN
BEGIN:VEVENT
UID:{uid}
DTSTAMP:{dtstamp}
DTSTART:{dtstart}
DTEND:{dtend}
SUMMARY:{title}
LOCATION:{location}
DESCRIPTION:{description}
END:VEVENT
END:VCALENDAR"""
return ics
# Usage
start = datetime(2026, 1, 25, 14, 0, 0)
end = datetime(2026, 1, 25, 15, 0, 0)
ics_content = create_ics("Team Meeting", start, end, "Conference Room A", "Discuss Q1 goals")
print(ics_content)
Tools for Working with ICS Files
- Text-2-ICS: Generate ICS from text, PDF, images
- ICS Viewer: Validate and preview ICS files
- RRULE Generator: Create recurring event rules
- Libraries:
- Python:
icalendar,ics - JavaScript:
ical.js,ics - PHP:
eluceo/ical - Ruby:
icalendar
- Python:
Skip the Manual Formatting
Generate RFC 5545-compliant ICS files from plain text in seconds.
Try Text-2-ICS →