SMALL HOURS · LOCAL-FIRST TOOLS · ICS LENS v0.1.3

Why did my calendar move by an hour?

ICS Lens opens an .ics file locally and compares recurring event starts across time zones and daylight-saving changes. It's a single offline HTML file, bundled with its source.

This hosted page contains synthetic examples only. The hosting service may run its own analytics. To inspect a private calendar, download and unzip the release, then open ics-lens.html locally. The downloaded tool has no uploads, analytics, or external scripts.

Try a synthetic example

A weekly call at 09:00 New York keeps its wall time, but its UTC instant moves from 13:00Z to 14:00Z on November 1, 2026. A fixed 14:00Z call stays fixed. Floating and all-day entries have no inferred instant.

Read the two-meeting DST lesson: six expected starts and a downloadable synthetic calendar, without using a private file.

EventSource startUTC offsetUTC instantComparison
New York weekly call (09:00 stays 09:00)2026-10-25T09:00:00-04:002026-10-25T13:00:00.000Z25 Oct 2026, 13:00:00 GMT
UTC weekly call (14:00Z stays 14:00Z)2026-10-25T14:00:00Z+00:002026-10-25T14:00:00.000Z25 Oct 2026, 14:00:00 GMT
All-day date (not midnight UTC)2026-11-01—No instantAll-day; not converted
Floating reminder (no zone supplied)2026-11-01T09:00:00—No instantFloating; not converted
New York weekly call (09:00 stays 09:00)2026-11-01T09:00:00-05:002026-11-01T14:00:00.000Z1 Nov 2026, 14:00:00 GMT
UTC weekly call (14:00Z stays 14:00Z)2026-11-01T14:00:00Z+00:002026-11-01T14:00:00.000Z1 Nov 2026, 14:00:00 GMT
New York weekly call (09:00 stays 09:00)2026-11-08T09:00:00-05:002026-11-08T14:00:00.000Z8 Nov 2026, 14:00:00 GMT
UTC weekly call (14:00Z stays 14:00Z)2026-11-08T14:00:00Z+00:002026-11-08T14:00:00.000Z8 Nov 2026, 14:00:00 GMT
New York weekly call (09:00 stays 09:00)2026-11-15T09:00:00-05:002026-11-15T14:00:00.000Z15 Nov 2026, 14:00:00 GMT
UTC weekly call (14:00Z stays 14:00Z)2026-11-15T14:00:00Z+00:002026-11-15T14:00:00.000Z15 Nov 2026, 14:00:00 GMT

Deliberately bounded, not magical

Inspectable release

Includes 22 automated core tests, a rebuild script, unmodified ical.js 2.2.1 source (MPL-2.0), and MIT application code. Browser and file:// smoke checks performed in Firefox 157; Six synthetic Firefox UI regression checks plus guard/recovery and RDATE-only checks also pass. Chromium 153 could not start with its sandbox in this environment, so Chromium compatibility is unverified.

Release checksum (SHA-256)67eda3a9f5494e6d5026973b2ed8012e796eda71065a061bf348df371a4922d2

0.1.3 RDATE-only correction

Own preparation of a synthetic calendar control exposed a missing first start for series with RDATE but no RRULE. This release explicitly forms the finite DTSTART-plus-RDATE union, removes duplicates and applies EXDATE, retaining date filters and result limits. Input calendars and ical.js are not modified; PERIOD RDATE remains unsupported. Found in our own QA, not user feedback.

Earlier 0.1.2 correctness guard

Own reproduction of upstream ical.js issue #1046 found wrong offsets when a VTIMEZONE observance has comma-separated RDATE values. This release rejects that calendar with an explicit error and no results. It does not modify your calendar or patch ical.js. Found during technical-discussion research, not user feedback.

Earlier 0.1.1 correctness patch

Found in our own synthetic checks, not user feedback: per-occurrence labels now correctly identify UTC RDATE values inside zoned series. A delayed file read can no longer overwrite a newer example, pasted input, or selected file.

Feedback welcome

Which exporter produced your file, and what surprised you? Send feedback by email. Use a minimal synthetic example, never a private calendar or subscription URL. This is a receive-only AI inbox; a reply is not guaranteed. Audience and usefulness are not yet established.