piapia123
en

ICS Reader

Convert

Everything runs locally in your browser — nothing is uploaded

Input
Drop a file here to load its contents
Output

`.ics` is the common calendar exchange format (RFC 5545) — what Google Calendar, Outlook and Apple Calendar export. The problem is not that you cannot open it, but that it is hard to read: each event is a `BEGIN:VEVENT` block, and the thing you want (“next Thursday at three, weekly, until the end of the year”) is scattered across `DTSTART`, `RRULE` and `UNTIL`, with dozens of lines of `VTIMEZONE` definitions in between. This reads it into a table. ⚠️ By default nothing is converted: a time with a `TZID` is shown as the clock time the file states, labelled with the zone. That is the raw fact and a conversion is a derived one — they are listed separately so you can check the conversion. To convert, put an IANA zone name in the options (`Asia/Shanghai`, `America/New_York`, `UTC`) and every event gains a row saying what that instant is in your chosen zone, with the UTC offset for that day. ⚠️ This is not subtracting a fixed offset: the offset comes from the platform’s time zone database, so it is taken on the event’s own date (New York is −05:00 in January and −04:00 in July) and historical rule changes are included. Two edge cases are called out rather than quietly resolved: a clock time skipped by a daylight-saving change does not exist in that zone (it is not nudged to a neighbour), and one repeated by a fall-back maps to two instants (the earlier is used, and noted). ⚠️ Separately, a time with neither `Z` nor a zone name is a floating time: the same wall-clock hour wherever it is read. That is a different thing from a fixed instant, and it is labelled as such here. Any such times come with an explanatory note in the result. Everything runs in your browser.

Features

  • Per event: summary, start and end, duration, location, description (optional), status, UID
  • Organizer and all attendees (the `CN` name when present, otherwise the address)
  • ⚠️ Recurrence rules rendered as a sentence — “weekly (Thu), 4 times in total” rather than `FREQ=WEEKLY;BYDAY=TH;COUNT=4`
  • ⚠️ Unrecognised recurrence modifiers are appended verbatim — no pretending they were understood, because those conditions decide whether a given occurrence happens at all
  • Alarm count (the `VALARM` sub-components)
  • All-day events marked as such, with the duration counted in days
  • Summary: number of events, how many repeat, how many have alarms, and the overall date range
  • ⚠️ Handles RFC 5545 line folding correctly (75-octet lines, continuations starting with a space) — get it wrong and text gains spaces or splits mid-word
  • ⚠️ By default nothing is converted; it reports the clock time from the file and labels the zone or “floating”
  • ⚠️ Optionally view everything in any zone: give an IANA name and each event gains a converted row with that day’s UTC offset
  • The offset is taken on the event’s own date, not today — two dates on either side of a daylight-saving change give different offsets
  • A clock time skipped by a daylight-saving change (it does not exist in that zone) and one repeated by a fall-back (two instants) are both flagged rather than quietly nudged
  • The converted row sits alongside the as-written row; the original is never replaced
  • Runs entirely in your browser; the file is never uploaded

How to use

  1. Paste the whole .ics file, from BEGIN:VCALENDAR to END:VCALENDAR
  2. Tick “also output the descriptions” if you want the event bodies
  3. The result lists each event as a block, with a time zone note at the end

FAQ

Why not convert the times to my time zone?
By default it does not convert, because what the file states is the raw fact and a conversion is derived from it — listing both side by side is what lets you check the conversion. To convert, put an IANA zone name in the options. ⚠️ Even then it is not subtracting a fixed offset: the offset comes from the platform’s time zone database for that date (daylight-saving rules have changed many times, so it is no constant — a fixed value for `Europe/London` is an hour out for months of the year). Clock times skipped by a daylight-saving change, or repeated by a fall-back, are flagged rather than nudged to a neighbour, because a wrong time is worse than no time.
What is a “floating time”?
A time with no `Z` suffix and no zone name means, in iCalendar, “this wall-clock hour locally” — so an event at 14:00 is at 14:00 for a reader in Tokyo and in London alike. That suits things like “take this at 7 am daily” where the location is irrelevant. Treat it as a fixed instant and convert it, and you get a result that looks reasonable and is wrong. So it is labelled here.
Why do some recurrence summaries end with a string of `BY...=`?
Because those are the modifiers that were not understood, and they are often exactly what decides whether a particular occurrence happens. For instance `BYDAY=-1FR` (the last Friday of the month) and `BYSETPOS=-1` (take the last of the set) are each recognisable alone, but their combination needs a full expansion algorithm to pin down. Only the recognised parts are rendered as a sentence; the rest are appended verbatim. Better that you see the raw condition than get a sentence that reads smoothly and silently drops a constraint.
Why is the text in descriptions sometimes run together?
That usually means the file was rewritten by another tool. RFC 5545 caps a line at 75 octets, with the remainder folded onto the next line starting with a single space; correct unfolding is plain concatenation with no separator. Some tools re-save with their own line-breaking, or unfold by inserting a space, so the text comes back with extra spaces. This follows the standard — if the spacing looks odd, the source is whoever produced the file.
Can I export this to CSV?
Not currently. The whole result can be copied, and every row value is individually copyable, which is enough to paste into a spreadsheet. Bulk-processing dozens of calendar files is beyond what pasting into a browser page is for anyway.

Related tools