CSV to ICS

Paste a spreadsheet of events — title, start, end — and get back a standards-compliant .ics calendar file you can import into Google Calendar, Outlook or Apple Calendar. Nothing leaves your browser.

Try:
ICS calendar

About this tool

Calendars import .ics files; spreadsheets export CSV. This tool is the missing step between them. Paste a table of events — one row per event, with a header row naming the columns — and it hands back a standards-compliant iCalendar document you can save as schedule.ics and import into Google Calendar, Outlook, Apple Calendar, Thunderbird or anything else that speaks iCalendar.

The conversion runs as WebAssembly inside this page, so your schedule never leaves the browser tab. The output is deterministic too: the same CSV always produces the same bytes, which keeps re-imports and version-controlled calendar files clean.

A worked example

Paste this, leave every option alone:

title,start,end,location
Team sync,2026-07-24 09:00,2026-07-24 09:30,Room 2
Conference,2026-07-27,2026-07-29,Berlin

You get back:

BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//gizza-ai//csv-to-ics//EN
CALSCALE:GREGORIAN
BEGIN:VEVENT
UID:[email protected]
DTSTAMP:19700101T000000Z
DTSTART:20260724T090000
DTEND:20260724T093000
SUMMARY:Team sync
LOCATION:Room 2
END:VEVENT
BEGIN:VEVENT
UID:[email protected]
DTSTAMP:19700101T000000Z
DTSTART;VALUE=DATE:20260727
DTEND;VALUE=DATE:20260730
SUMMARY:Conference
LOCATION:Berlin
END:VEVENT
END:VCALENDAR

The first row had a time, so it became a half-hour timed event. The second had bare dates, so it became a three-day all-day event — note the DTEND of the 30th, because iCalendar all-day ends are exclusive and the tool adds that day for you.

Columns it recognises

Header names are matched without regard to case, spaces, hyphens or underscores, so Start Date, start_date and START-DATE are the same column. Anything unrecognised is ignored rather than rejected.

Dates, times and lengths

Dates are written as 2026-07-24, 2026-07-24 09:00 or 2026-07-24T09:00, with optional seconds. A start with no time — or a truthy all-day cell — makes an all-day event written as VALUE=DATE. Anything else is a timed event, and it ends at its end cell, else its duration_minutes cell, else the default event length (60 minutes unless you move the slider).

The timezone choice decides how timed events are anchored. Floating writes DTSTART:20260724T090000 with no zone marker, so 09:00 shows as 09:00 wherever the event is opened — the right choice for a class timetable or a personal schedule. UTC treats the pasted times as already being UTC and writes them with the trailing Z, so each calendar converts them into its own local time — the right choice for a release plan or a call across several countries. All-day events carry no time either way.

Limits and edge cases

FAQ

How do I get the .ics file into Google Calendar?

Copy the output into a text editor and save it with an .ics extension, then open Google Calendar on the web, go to Settings → Import & export, choose the file and pick the calendar to add the events to. Outlook uses File → Open & Export → Import/Export → Import an iCalendar (.ics) file, and Apple Calendar imports with File → Import. Import into a new, empty calendar the first time — that way you can delete the whole calendar in one click if the mapping was not what you wanted.

Why is my event showing up as all-day when I wanted a time?

The start cell had no time in it. 2026-07-24 is a date, so it becomes an all-day event; 2026-07-24 09:00 is a moment, so it becomes a timed one. Spreadsheets often strip the time from a column formatted as a date — check the exported CSV in a plain text editor rather than in the spreadsheet. If your times live in a separate column, join them into the start column first (=A2&" "&TEXT(B2,"HH:MM") in most spreadsheets).

My multi-day event is one day short. What happened?

Nothing — check the dates in your calendar rather than in the .ics text. iCalendar all-day ends are exclusive, so an event running the 27th through the 29th is written as DTEND on the 30th. This tool adds that day for you, which means you should enter the last day the event actually runs, not the day after it.

Should I pick floating or UTC?

Pick floating when everyone attends in their own local time — a school timetable, a conference agenda handed to attendees who are all on site, a personal routine. 09:00 then means 09:00 on whatever clock the reader has. Pick UTC when the events are fixed instants that people join from different countries — a release window, a global standup — and paste times you have already converted to UTC, so each calendar shows the correct local time. There is no per-row timezone column: convert the times before pasting if the rows are mixed.

Can I add reminders and descriptions?

Yes. Add a description, details or notes column and its text lands in each event's DESCRIPTION, and a location or place column fills LOCATION. Turn on "Add a 15-minute reminder" to attach a pop-up alarm to every event. That reminder is all-or-nothing and fixed at 15 minutes before the start; for an all-day event it fires 15 minutes before midnight, so leave it off for holiday or deadline calendars.

Is anything uploaded?

No. The conversion is a WebAssembly module running in this page, so your event list stays in the browser tab. You can load the page, disconnect from the network and it still works. The same conversion is available offline in the command-line tool if you would rather script it.

Developer & Automation Access

Run it from the terminal

Same engine as this page, headless — via the gizza CLI:

gizza tool csv-to-ics "title,start,end,location
Team sync,2026-07-24 09:00,2026-07-24 09:30,Room 2
Conference,2026-07-27,2026-07-29,Berlin"

New to the CLI? Get gizza →

Open it by URL

Pre-fill and auto-run this tool with query parameters — the names match the API/CLI:

https://gizza.ai/tools/csv-to-ics/?csv=title%2Cstart%2Cend%2Clocation%0ATeam%20sync%2C2026-07-24%2009%3A00%2C2026-07-24%2009%3A30%2CRoom%202%0AConference%2C2026-07-27%2C2026-07-29%2CBerlin&timezone=floating&default_duration_minutes=60&include_alarm=true

Machine-readable descriptor: tool.json — title + parameters JSON Schema for agents.