How to Compare Two ICS Files for Real Calendar Changes
Compare two ICS files by event identity, scheduled fields, recurrence exceptions, and source differences without confusing export formatting with calendar changes.
On this page
To compare two ICS files, match events by their identities before reviewing dates and other fields. Then inspect the raw source differences. A text diff alone can exaggerate reformatting, while a calendar preview can hide changes to attendees, recurrence rules, or metadata.
Use three questions: Is it the same event? What changed in its data? Does that change the schedule or workflow? Keep uncertain matches separate from confirmed edits.
Key Takeaways
- Match recurring exceptions with both
UIDandRECURRENCE-ID.- Review added, removed, and changed records separately.
- Timestamp and formatting changes deserve inspection even when meeting times are unchanged.
- An event missing from a later export is not proof that a cancellation was sent.
Establish which export is the baseline
Name the files clearly, such as before.ics and after.ics. Record the source account, calendar, export date, and date-range settings.
If the first export covers a full year and the second covers one month, “removed” can mean “outside the export range.” Likewise, an export made with reduced detail can omit descriptions or guests without anyone editing the live events.
Keep both originals. Compare copies so saving a normalized version does not overwrite the evidence.
Use a controlled pair before a private calendar
This synthetic baseline contains three independent events. Save it with UTF-8 encoding and CRLF line endings.
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//CalendarLint//Comparison Example//EN
BEGIN:VEVENT
UID:review@example.test
DTSTAMP:20261105T000000Z
DTSTART:20261110T090000Z
DTEND:20261110T093000Z
SUMMARY:Design review
END:VEVENT
BEGIN:VEVENT
UID:archive@example.test
DTSTAMP:20261105T000000Z
DTSTART:20261111T140000Z
DTEND:20261111T143000Z
SUMMARY:Archive check
END:VEVENT
BEGIN:VEVENT
UID:notes@example.test
DTSTAMP:20261105T000000Z
DTSTART:20261112T100000Z
DTEND:20261112T103000Z
SUMMARY:Planning notes
DESCRIPTION:Bring the draft agenda.
END:VEVENT
END:VCALENDAR
Create after.ics from a copy with these exact edits:
- Keep
review@example.test, but move its start to20261110T110000Zand end to20261110T113000Z. - Remove the entire
archive@example.testevent. - Keep the notes event's fields, but move its
DESCRIPTIONline aboveSUMMARY. - Add the following component before
END:VCALENDAR:
BEGIN:VEVENT
UID:handoff@example.test
DTSTAMP:20261105T000000Z
DTSTART:20261113T150000Z
DTEND:20261113T153000Z
SUMMARY:Project handoff
END:VEVENT
These instructions fully define the second input without hiding changes inside an unrelated sample download.
Check the expected differences
The controlled pair should produce this human interpretation:
| Identity | Expected change | Meaning |
| --- | --- | --- |
| review@example.test | Start and end move two hours later | Same event, changed schedule |
| archive@example.test | Record absent from the second file | Removed from this export |
| notes@example.test | Property order changes | No intended change to event values |
| handoff@example.test | New record in the second file | Added to this export |
The property reorder is useful because it makes the raw diff visibly different without changing the notes event's values. It is one controlled case, not evidence that a comparison tool recognizes every form of semantic equivalence.
Compare the files in CalendarLint
Open the baseline, then use ICS Files and its version controls. For a separate publisher export, choose Compare a new ICS file. For a repair saved inside the project, compare the saved version against the original.
The comparison provides All, Events, Issues, and Source views, as described in the version comparison workflow. Use Events to inspect the changed records and Source to verify the actual lines.
For the controlled pair, check that the design review retains its identity, the handoff is added, the archive check is removed, and the property reorder has no intended schedule effect. Review the source even when the event summary looks unsurprising.
The current comparison implementation groups records using UID and recurrence identity. This supports ordinary retained-identity edits; it does not establish the publisher's intent when identities change.
Handle recurrence and ambiguous identities explicitly
A moved occurrence belongs to its original recurrence slot. RECURRENCE-ID identifies that slot; its new DTSTART can be different. Matching only the new date can misclassify a move as a deletion and addition (RFC 5545, recurrence identity).
If the exporter generates new UIDs, the two files may show an old record removed and a new one added. Similar titles and times can suggest a relationship, but they are not conclusive evidence. Ask the publisher whether identity was regenerated.
Also check:
- Duplicate records with the same UID and recurrence identity.
RRULE,RDATE, andEXDATEchanges that affect dates beyond the current preview.VTIMEZONEchanges that can alter interpretation without changing a local clock value.- Organizer, attendee, status, and alarm changes that affect behavior without moving the event.
A finite recurrence preview cannot prove equivalence for an unbounded series. Compare the rules and relevant future boundaries as well.
Decide what to keep before exporting
Treat DTSTAMP, SEQUENCE, and LAST-MODIFIED as metadata to interpret, not automatically discard. A metadata-only change may leave the visible schedule unchanged while still mattering to a meeting update process.
Write down the expected changes before accepting a repaired version. Then check identities, dates, recurrence exceptions, and unrelated fields against that list. Download the verified version with a distinct filename and keep the originals.
Verification scope: the controlled pair was parsed and checked locally with ical.js 2.2.1 on November 5, 2026. CalendarLint comparison behavior was checked against the current source and its existing comparison tests. No universal equivalence detection or cross-client import result is claimed.

