Commit574db51fRecorded26 Mar 2026Repositorysigil-caldav
Fix CalDAV timezone offset bug: use mktime for correct DST handling
Message
parse-ical-datetime was using time-utc-offset (current moment's offset) to convert local datetimes to UTC, causing 1-hour errors when parsing events in a different DST season. Now delegates to list->time (mktime) which correctly resolves the offset for any date.
Also adds time-utc-offset-at to (sigil time) for timestamp-specific offset queries, extracts shared utcoffsetfor_time helper in time.c.
Changed
src/sigil/caldav/ical.sgl | 9 ++++-----
test/test-caldav.sgl | 13 +++++++++++--
2 files changed, 15 insertions(+), 7 deletions(-)Diff
src/sigil/caldav/ical.sglmodified
@@ -151,12 +151,11 @@
151
(d (string->number (substring str 6 8))) 152
(h (string->number (substring str 9 11))) 153
(mi (string->number (substring str 11 13)))−154
(s (string->number (substring str 13 15)))−155
(ts (utc->timestamp y mo d h mi s)))+154
(s (string->number (substring str 13 15)))) 155
(if utc?−157
ts−158
;; Local time: subtract UTC offset to get the correct Unix timestamp−159
(- ts (time-utc-offset)))))+156
(utc->timestamp y mo d h mi s)+157
;; Local time: delegate to mktime for correct DST handling+158
(list->time (list s mi h d mo y))))) 159
160
;;; Parse an iCalendar date string to a Unix timestamp. 161
;;;test/test-caldav.sglmodified
@@ -21,8 +21,17 @@
21
(test "parses local datetime in system timezone" 22
(let* ((ts-local (parse-ical-datetime "20240315T090000")) 23
(ts-utc (parse-ical-datetime "20240315T090000Z")))−24
;; Local time differs from UTC by the timezone offset−25
(assert-equal (- ts-utc (time-utc-offset)) ts-local)))+24
;; Local time differs from UTC by the offset at that date+25
(assert-equal (- ts-utc (time-utc-offset-at ts-utc)) ts-local)))+26
+27
(test "local datetime uses date-specific offset, not current offset"+28
;; Parse two dates in different DST periods and verify correct offsets.+29
(let* ((winter-local (parse-ical-datetime "20260115T120000"))+30
(winter-utc (parse-ical-datetime "20260115T120000Z"))+31
(summer-local (parse-ical-datetime "20260715T120000"))+32
(summer-utc (parse-ical-datetime "20260715T120000Z")))+33
(assert-equal (- winter-utc (time-utc-offset-at winter-utc)) winter-local)+34
(assert-equal (- summer-utc (time-utc-offset-at summer-utc)) summer-local))) 35
36
(test "round-trips midnight" 37
(let ((ts (parse-ical-datetime "20240101T000000Z")))