events: timezone + DST support + 17 tests
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 1m5s

timezone.sx: wall-clock LOCAL <-> absolute UTC. :fixed + :dst zones (std/dst
offsets + UTC transition rules, EU-style, no IANA DB) computed via calendar
helpers. ev-event-tz authors in local time; ev-expand expands tz events in
LOCAL time then converts each occurrence to UTC, so a 09:00 weekly meeting
stays 09:00 across a DST change (UTC instant shifts). Predefined utc/london/
paris. Plain events unaffected. 295/295 green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-07 09:31:11 +00:00
parent c991c7c3d3
commit bf7bd38010
7 changed files with 339 additions and 8 deletions

View File

@@ -545,10 +545,9 @@
(list orig-start {:start new-start :duration new-duration})
(ev-or (get event :overrides) (list))))))
;; Expand an event into occurrence dicts within the window, applying any
;; EXDATE/RDATE exceptions and per-occurrence overrides. Public entry point.
;; Naive (single time-domain) expansion: RRULE + EXDATE/RDATE + overrides.
(define
ev-expand
ev-expand-naive
(fn
(event win-start win-end)
(let
@@ -567,6 +566,20 @@
(fn (o) (and (>= (get o :start) win-start) (<= (get o :start) win-end)))
(ev-sort-occs (ev-apply-overrides id excepted overrides)))))))
;; Public entry point. A tz-aware event (`:tz` set) expands in local wall-clock
;; time and converts each occurrence to UTC (ev-expand-tz, timezone.sx); a plain
;; event expands naively in a single time domain. The window is UTC either way.
(define
ev-expand
(fn
(event win-start win-end)
(let
((tz (get event :tz)))
(if
(nil? tz)
(ev-expand-naive event win-start win-end)
(ev-expand-tz event tz win-start win-end)))))
;; ---- multi-event expansion (sorted by start) ----
;; Insertion of one occurrence into a start-ascending list.