ICS/iCalendar Reference (RFC 5545)
A technical reference for the iCalendar format: calendar structure, VEVENT properties, date-time handling, recurrence rules, and conversion to CSV and JSON.
What Is ICS/iCalendar?
iCalendar (ICS) is the universal calendar data exchange format, standardized as RFC 5545 (published September 2009 by B. Desruisseaux, replacing RFC 2445). It is a text-based format with a MIME content type of text/calendar. ICS files are used by Google Calendar, Apple Calendar, Microsoft Outlook, and virtually every calendar application to share event data.
The format's design goal is interoperability: a single .ics file should be importable into any compliant calendar application without modification. It supports events (VEVENT), to-dos (VTODO), journal entries (VJOURNAL), free/busy time (VFREEBUSY), and timezone definitions (VTIMEZONE).
ICS File Structure
Every ICS file is a flat text file wrapped in BEGIN:VCALENDAR / END:VCALENDAR markers. Within this wrapper, the file contains one or more components (most commonly VEVENT), each with a set of properties.
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//JSON CSV Tools//Converter v1.0//EN
BEGIN:VEVENT
UID:[email protected]
DTSTART:20260615T090000Z
DTEND:20260615T100000Z
SUMMARY:Team Standup
DESCRIPTION:Daily engineering sync — Zoom link in chat
LOCATION:Conference Room B
ORGANIZER;CN=Alice:mailto:[email protected]
STATUS:CONFIRMED
DTSTAMP:20260612T210000Z
END:VEVENT
END:VCALENDAR
The calendar-level properties (VERSION, PRODID) apply to the entire file. VERSION must be 2.0 for any modern ICS file. PRODID identifies the software that generated the file — it's good practice to include one, though many parsers accept its absence.
VEVENT Fields
| Property | Required | Description |
|---|---|---|
DTSTART | Yes | Start date/time of the event. Can be DATE or DATE-TIME. |
DTEND | No | End date/time. For all-day DATE events, this is exclusive (the day after the last day). |
SUMMARY | No | Short title or subject of the event. |
DESCRIPTION | No | Longer description. Supports escaped newlines (\n) and limited HTML in some clients. |
LOCATION | No | Physical or virtual location (room name, address, URL). |
UID | Yes | Globally unique identifier. Must be unique across all calendars. Typically a UUID or email-style identifier. |
DTSTAMP | Yes (RFC 5545) | Date-time the iCalendar object was created. Many generators set this automatically. |
STATUS | No | TENTATIVE, CONFIRMED, or CANCELLED. |
ORGANIZER | No | The event organizer, typically a mailto: URI with optional CN parameter for display name. |
ATTENDEE | No | One per invitee. Includes participation status via PARTSTAT parameter. |
Date-Time Handling
ICS supports three date-time forms, and getting them right is essential for correct calendar import:
- DATE-TIME with UTC (Z suffix).
DTSTART:20260615T140000Z— a specific moment in UTC. The safest and least ambiguous form. Calendar clients convert to the user's local timezone for display. - DATE-TIME with timezone reference.
DTSTART;TZID=America/New_York:20260615T100000— local time in the named timezone. Requires the corresponding VTIMEZONE component to be defined in the ICS file (or the client must recognize the TZID). - DATE (all-day).
DTSTART;VALUE=DATE:20260615— a calendar date with no time component. For all-day events, DTEND (if present) should also be DATE and represents the exclusive end (the day after the event). A one-day event has DTSTART=20260615 and DTEND=20260616.
Floating time (DATE-TIME without Z or TZID) represents the same clock time everywhere: DTSTART:20260615T090000 means 9:00 AM regardless of timezone. This is risky for multi-timezone calendars — a 9:00 AM floating start will appear as 9:00 AM in New York and 9:00 AM in London, not the same moment.
Recurrence: RRULE
Recurring events use the RRULE property rather than listing each occurrence individually:
RRULE:FREQ=WEEKLY;BYDAY=MO,WE,FR;UNTIL=20261231T235959Z
Key RRULE parts:
| Part | Description |
|---|---|
FREQ | Recurrence frequency: DAILY, WEEKLY, MONTHLY, YEARLY |
INTERVAL | Every N periods. INTERVAL=2 with FREQ=WEEKLY means every other week. |
UNTIL | End date for the recurrence (inclusive by default in RFC 5545). Mutually exclusive with COUNT. |
COUNT | Number of occurrences. COUNT=10 produces exactly 10 instances. |
BYDAY | Days of the week: MO,TU,WE,TH,FR,SA,SU |
BYMONTHDAY | Days of the month: 1,15,-1 (1st, 15th, last day) |
Exceptions to a recurrence rule are defined with EXDATE, which lists specific date-times to skip. This is how you delete a single instance of a recurring meeting without cancelling the entire series.
Alarms: VALARM
The VALARM component defines reminders attached to an event. It appears inside VEVENT:
BEGIN:VALARM
TRIGGER:-PT15M
ACTION:DISPLAY
DESCRIPTION:Standup starting in 15 minutes
END:VALARM
TRIGGER specifies when the alarm fires relative to the event start. -PT15M means 15 minutes before. The ACTION property supports DISPLAY (show a message), AUDIO (play a sound), and EMAIL (send notification).
ICS→CSV Conversion
Converting ICS to CSV involves selecting which VEVENT properties map to columns:
| ICS Property | CSV Column | Notes |
|---|---|---|
| UID | uid | Direct mapping |
| DTSTART | start_date, start_time | Often split into separate date and time columns for readability |
| DTEND | end_date, end_time | Same treatment as DTSTART |
| SUMMARY | title | Direct mapping |
| DESCRIPTION | description | Newlines may need escaping for CSV compliance |
| LOCATION | location | Direct mapping |
| ORGANIZER | organizer | Extract display name (CN) or email |
| RRULE | rrule | Options: expand into rows, or preserve as string |
Recurring events pose the biggest ICS→CSV challenge. The RRULE defines a pattern, not individual instances. To get one row per occurrence, the converter must expand the RRULE into concrete dates. Our ICS to CSV converter does this expansion within a configurable date window. See the format comparison guide for a broader view of conversion trade-offs.
VTIMEZONE components are another challenge: ICS files may include timezone definitions with daylight saving rules. Converting a TZID-referenced date-time to a flat CSV string requires resolving the timezone — either to UTC or to a user-specified local time.
Common ICS Issues
- Missing UID. Some generators omit UID, but most calendar clients require it. Without a UID, the client creates one on import, which means re-importing the same file creates duplicates instead of updates.
- Duplicate UIDs. When you export the same calendar twice, every event has the same UID. Importing both files into another calendar causes the second import to update (overwrite) the first rather than creating new events. If you need copies, generate new UIDs.
- Incorrect line folding. RFC 5545 specifies a 75-octet line-length limit. Lines exceeding this must be folded with CRLF followed by a single space. While most modern parsers handle long lines, some strict implementations (and older calendar clients) will reject unfolded files.
- Timezone mismatches. Using
TZID=America/New_Yorkwithout including the corresponding VTIMEZONE definition is a common error. Not all clients ship with the full Olson timezone database. - All-day event timezone shift. An all-day event with
VALUE=DATEis timezone-independent. If you accidentally use DATE-TIME for a birthday or holiday, the event can appear on the wrong day in other timezones.
Frequently Asked Questions
Why doesn't my ICS file import into Google Calendar?
The most common cause is a missing or duplicate UID. Google Calendar requires every VEVENT to have a globally unique UID property. If two events share the same UID (common when re-exporting the same calendar), Google Calendar treats the second as an update to the first rather than as a new event. Other common causes: missing DTSTART (required for VEVENT), incorrect line folding (ICS requires lines longer than 75 octets to be folded with CRLF followed by a space), or timezone references to a VTIMEZONE that isn't included in the file. Validate your ICS with an iCalendar validator to catch these issues quickly.
How do I handle recurring events when converting ICS to CSV?
Recurring events are defined by an RRULE property, not by individual VEVENT instances. When converting ICS to CSV, you have two options: (1) expand the recurrence into individual rows — one CSV row per occurrence — using a library that understands RRULE expansion, or (2) preserve the RRULE string as a column value, which keeps the file small but requires the consumer to understand recurrence syntax. Option 1 is usually more practical for spreadsheets and data analysis. Our ICS to CSV converter expands recurrences within a configurable date range so you get one row per actual occurrence.
What's the difference between DATE and DATE-TIME in ICS?
DATE values (e.g., DTSTART;VALUE=DATE:20260615) represent an entire calendar day with no time component — think birthdays, holidays, or all-day events. DATE-TIME values (e.g., DTSTART:20260615T140000Z) represent a specific moment in time. If you specify a DATE-TIME without a timezone (floating time), it represents the same clock time regardless of timezone. The value type parameter is critical: a missing VALUE=DATE on an all-day event can cause it to appear at midnight UTC, which shifts the visible date in most timezones.
What is line folding in ICS and why does it matter?
Line folding is an RFC 5545 requirement: no line of content may exceed 75 octets (bytes). Longer lines must be split by inserting a CRLF followed by a single space character at or before the 75-octet limit. Many hand-written ICS files miss this, and while most modern parsers tolerate long lines, strict validators and some calendar clients (especially older ones) will reject unfolded files. If your ICS file fails to import with no clear error, line-length violations are a likely suspect.