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")))