feat: add recurrence and time zone support

This commit is contained in:
2026-07-17 21:52:02 +01:00
parent 22c6399056
commit c19098004e
18 changed files with 2321 additions and 132 deletions

View File

@@ -27,6 +27,19 @@ optional descriptive fields, and calendar identity. Queries define overlap as
`event.start < range.end && event.end > range.start`; this matters for events
crossing midnight.
Recurring events remain one domain object. Occurrence queries expand only the
requested time window and return values that point back to their source series,
preserving series-level storage and mutation semantics. The supported rule
surface is deliberately bounded to daily/weekly/monthly/yearly frequency,
interval, count or until, weekly `BYDAY`, monthly `BYMONTHDAY`, yearly
`BYMONTH`, and `EXDATE`. Invalid metadata retains at most the base event rather
than crashing a render.
Timed events retain their source basis: UTC, floating process-local time, or an
IANA `TZID`. C++20 time-zone conversion keeps zoned recurrences at their civil
wall time across daylight-saving transitions. The month grid displays instants
in the user's local zone; the reader also names an explicit source zone.
## Storage
Version 0.1 uses a user-owned iCalendar file, defaulting to
@@ -50,11 +63,13 @@ rolls it back if persistence fails. Its bounded undo/redo history contains only
mutations that crossed the persistence boundary successfully.
The current writer deliberately refuses to mutate an existing file when the
loader encounters information it cannot round-trip, including recurrence,
alarms, attendees, time-zone identifiers, unknown properties, or malformed
components. Browsing remains available. This conservative boundary is more
important than partial editing because a successful-looking edit must not
erase unrelated calendar data.
loader encounters information it cannot round-trip, including recurrence
overrides, `RDATE`, custom `VTIMEZONE` definitions, alarms, attendees, unknown
properties, or malformed components. Supported recurrence rules, exclusions,
and system IANA time-zone identifiers round-trip semantically. Browsing remains
available for unsupported files. This conservative boundary is more important
than partial editing because a successful-looking edit must not erase unrelated
calendar data.
Provider synchronization will not write directly into this UI file. It will use
a transaction-capable local cache and preserve remote ETags/sync tokens in a