DEV Community

Michael Lip
Michael Lip

Posted on • Originally published at zovo.one

The ICS File Format: Creating Calendar Events That Work Everywhere

The ICS (iCalendar) format is a text-based standard for calendar events that every major calendar application supports: Google Calendar, Apple Calendar, Outlook, Thunderbird. When you click "Add to Calendar" on a website, you are downloading an .ics file. Understanding the format lets you programmatically generate calendar events for your applications.

The format

An ICS file is plain text with a specific structure:

BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Your App//EN
BEGIN:VEVENT
DTSTART:20260401T090000Z
DTEND:20260401T100000Z
SUMMARY:Team Standup
DESCRIPTION:Daily team sync meeting
LOCATION:Conference Room B
STATUS:CONFIRMED
UID:unique-id-12345@yourdomain.com
END:VEVENT
END:VCALENDAR
Enter fullscreen mode Exit fullscreen mode

Each event is a VEVENT block inside a VCALENDAR container. The required fields are DTSTART, SUMMARY, and UID. Everything else is optional but useful.

Date-time formats

ICS supports several date-time formats:

UTC (recommended): End with Z

DTSTART:20260401T090000Z
Enter fullscreen mode Exit fullscreen mode

Local time with timezone:

DTSTART;TZID=America/New_York:20260401T090000
Enter fullscreen mode Exit fullscreen mode

All-day events: Date only, no time

DTSTART;VALUE=DATE:20260401
DTEND;VALUE=DATE:20260402
Enter fullscreen mode Exit fullscreen mode

Note that all-day events use the day after as the end date. An all-day event on April 1st has DTEND of April 2nd. This is a common source of off-by-one errors.

Timezone handling is the trickiest part. If you use UTC times, the calendar application converts to the user's local timezone. If you use TZID, you need to include a VTIMEZONE component in the file that defines the timezone rules (including daylight saving transitions). For simplicity, use UTC whenever possible.

Recurring events

The RRULE property defines recurrence:

RRULE:FREQ=WEEKLY;BYDAY=MO,WE,FR;UNTIL=20261231T235959Z
Enter fullscreen mode Exit fullscreen mode

This creates an event every Monday, Wednesday, and Friday until the end of 2026. Other options:

RRULE:FREQ=MONTHLY;BYMONTHDAY=15      # 15th of every month
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU  # 2nd Sunday of March
RRULE:FREQ=DAILY;COUNT=10              # Daily for 10 occurrences
RRULE:FREQ=WEEKLY;INTERVAL=2           # Every other week
Enter fullscreen mode Exit fullscreen mode

Alarms and reminders

Add reminders with VALARM:

BEGIN:VALARM
TRIGGER:-PT15M
ACTION:DISPLAY
DESCRIPTION:Meeting in 15 minutes
END:VALARM
Enter fullscreen mode Exit fullscreen mode

TRIGGER:-PT15M means 15 minutes before the event start. -PT1H is one hour before. -P1D is one day before. You can include multiple VALARM blocks for multiple reminders.

Generating ICS files in code

function createICSEvent({ title, start, end, description, location }) {
  const formatDate = (date) => {
    return date.toISOString().replace(/[-:]/g, '').replace(/\.\d{3}/, '');
  };

  return [
    'BEGIN:VCALENDAR',
    'VERSION:2.0',
    'PRODID:-//MyApp//EN',
    'BEGIN:VEVENT',
    `DTSTART:${formatDate(start)}`,
    `DTEND:${formatDate(end)}`,
    `SUMMARY:${title}`,
    `DESCRIPTION:${description || ''}`,
    `LOCATION:${location || ''}`,
    `UID:${crypto.randomUUID()}@myapp.com`,
    `DTSTAMP:${formatDate(new Date())}`,
    'END:VEVENT',
    'END:VCALENDAR'
  ].join('
');
}
Enter fullscreen mode Exit fullscreen mode

The line endings must be
(CRLF) per the spec. Some calendar apps are forgiving about this; others are not.

Common pitfalls

Line length. The spec limits lines to 75 octets. Longer lines must be folded: insert
(CRLF followed by a space) to continue on the next line. Most calendar apps handle unfold lines, but spec compliance prevents edge cases.

Special characters. Commas, semicolons, and backslashes in property values must be escaped: \, \; \. Newlines in description fields use
.

UID uniqueness. Each event must have a globally unique UID. If you send an updated .ics file with the same UID, calendar apps treat it as an update to the existing event rather than a new event. This is a feature for event updates but a bug if your UIDs collide accidentally.

I built an ICS calendar generator at zovo.one/free-tools/ics-calendar-generator that creates properly formatted .ics files with support for all-day events, recurring events, reminders, timezone handling, and multi-event calendars. Fill in the event details and download a file that works in every calendar application.


I'm Michael Lip. I build free developer tools at zovo.one. 500+ tools, all private, all free.

Top comments (0)