{
  "slug": "csv-to-ics",
  "name": "gizza-ai/csv-to-ics",
  "version": "0.1.0",
  "title": "CSV to ICS — turn a spreadsheet of events into a calendar file — gizza.ai",
  "description": "Paste a CSV of events and get an .ics calendar file to import into Google Calendar, Outlook or Apple Calendar. Free, private, runs in your browser.",
  "tags": [
    "csv to ics",
    "csv to ical",
    "csv to calendar",
    "ics generator",
    "ics file creator",
    "import csv into google calendar",
    "spreadsheet to calendar",
    "icalendar converter"
  ],
  "category": "data",
  "urls": {
    "page": "https://gizza.ai/tools/csv-to-ics/",
    "markdown": "https://gizza.ai/tools/csv-to-ics/index.md",
    "descriptor": "https://gizza.ai/tools/csv-to-ics/tool.json",
    "deep_link_example": "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"
  },
  "cli": "gizza tool csv-to-ics \"title,start,end,location\nTeam sync,2026-07-24 09:00,2026-07-24 09:30,Room 2\nConference,2026-07-27,2026-07-29,Berlin\"",
  "tool": {
    "description": "Turn a CSV event list into an iCalendar (.ics) file that Google Calendar, Outlook, Apple Calendar and every other calendar app can import. Paste the CSV into `csv` with a header row; column names are matched case- and punctuation-insensitively, so `Start Date`, `start_date` and `START-DATE` are the same column. A title column (title, summary, name or event) and a start column (start, start_date, begins or date) are required; end/end_date/ends, duration_minutes/duration, description/details/notes, location/place, uid/id and all_day/all-day are optional. Dates are 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 with the exclusive DTEND calendars expect, so a 24th–26th conference imports as three days. A timed row ends at its end cell, else its duration_minutes, else default_duration_minutes (60). `timezone` picks floating local times (default) or UTC times with the trailing Z. `include_alarm` adds a 15-minute pop-up reminder to every event. Output is one VCALENDAR with a VEVENT per row, RFC 5545 CRLF endings, 75-octet line folding and escaped text; UIDs come from the uid column or are generated from the title, and DTSTAMP is fixed, so the same CSV always converts to the same bytes. Up to 5000 rows per run; a row with an unreadable date, a bad duration or an end before its start is reported by row number instead of silently dropped.",
    "parameters": {
      "additionalProperties": false,
      "properties": {
        "csv": {
          "description": "The event list as CSV text, first row naming the columns. Quoted cells (\"Lunch, with team\") are read as one value. Columns are matched case- and punctuation-insensitively: title/summary/name/event and start/start_date/begins/date are required, and end/end_date/ends, duration_minutes/duration, description/details/notes, location/place, uid/id and all_day/all-day are optional. Dates are 2026-07-24, 2026-07-24 09:00 or 2026-07-24T09:00, each with optional seconds; a start with no time makes an all-day event. Up to 5000 rows per run.",
          "type": "string"
        },
        "default_duration_minutes": {
          "default": 60,
          "description": "How long a timed event lasts, in minutes, when its row gives neither an end nor a duration_minutes cell. 60 by default, 1–1440 (one day). A row's own end or duration_minutes column always wins over this, and all-day rows ignore it.",
          "maximum": 1440,
          "minimum": 1,
          "type": "integer"
        },
        "include_alarm": {
          "default": false,
          "description": "Add a pop-up reminder 15 minutes before every event (a VALARM with ACTION:DISPLAY and the event title as its message). Off by default. For an all-day event this fires 15 minutes before midnight on the day it starts, so leave it off for holiday or deadline calendars.",
          "type": "boolean"
        },
        "timezone": {
          "default": "floating",
          "description": "How the times in the CSV are anchored. \"floating\" (default) writes them with no zone marker, so every calendar shows 09:00 as 09:00 in whatever timezone the reader is in — right for a schedule everyone attends locally. \"utc\" treats the pasted times as already being UTC and writes them with the trailing Z, so clients convert them to each person's own zone. All-day rows are unaffected either way.",
          "enum": [
            "floating",
            "utc"
          ],
          "type": "string"
        }
      },
      "required": [
        "csv"
      ],
      "type": "object"
    }
  }
}