This tool re-stamps the datetimes inside an iCalendar (.ics) file so an event written in one timezone reads correctly in another. It is useful when you export a calendar that was authored in, say, London time and need to hand it to someone who works in New York, or when a feed was generated in the wrong zone and every event is off by a fixed number of hours.
How it works
iCalendar datetimes appear in a few forms:
- Zoned —
DTSTART;TZID=Europe/London:20260615T090000(wall-clock time plus a named zone). - UTC —
DTSTART:20260615T080000Z(the trailingZmarks Coordinated Universal Time). - All-day —
DTSTART;VALUE=DATE:20260615(a date with no time).
The shifter parses each DTSTART, DTEND, EXDATE, RDATE and RECURRENCE-ID property. For every value that has a time component it performs two steps:
- Resolve to an absolute instant. The wall-clock time is combined with the source zone’s UTC offset for that specific date to get the exact moment in time. Because offsets change across daylight-saving boundaries, this is computed per datetime, not as a single fixed shift.
- Re-express in the target zone. That absolute instant is converted back into the target zone’s wall-clock time, and the
TZIDparameter is updated to match (or replaced with aZsuffix when the target is UTC).
The offset lookups use Intl.DateTimeFormat with your browser’s built-in IANA timezone database, so they include the correct historical and seasonal rules.
What is left unchanged
All-day entries (VALUE=DATE) carry no time, so shifting them would be meaningless — they are passed through untouched and counted separately. Property names, summaries, descriptions and recurrence rules are preserved exactly; only the datetime values move.
Example
An event written as Europe/London 09:00 in mid-June (British Summer Time, UTC+1) shifted to America/New_York (Eastern Daylight Time, UTC−4) becomes 04:00 New York time — a 5-hour difference for that date. A January event between the same two zones shifts by a different amount because both zones are on standard time.
Everything runs locally in your browser — your calendar is never uploaded.