diff options
| author | Craig Jennings <c@cjennings.net> | 2026-01-27 08:18:43 -0600 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-01-27 08:18:43 -0600 |
| commit | d7bef9bbf6ad41502981466638811e3c8e736111 (patch) | |
| tree | 2d7b88e063cd9fab42b7bd21065c04c26d1b3661 /modules | |
| parent | 31355b5e0472e86842df9ce278000677bdaf4e71 (diff) | |
fix(calendar-sync): resolve freeze on DST transitions and large ICS files
Two bugs caused Emacs to freeze during calendar sync:
1. split-events used catastrophic regex (\(.\|\n\)*?) on multi-MB ICS
data. Replaced with buffer-based search-forward (0.011s for 4.5MB).
2. add-days used midnight for date arithmetic. On DST fall-back days,
adding 86400s to midnight CDT yields 11pm CST (same date), creating
an infinite loop. Fixed by using noon so ±1h DST shift stays correct.
Diffstat (limited to 'modules')
| -rw-r--r-- | modules/calendar-sync.el | 20 |
1 files changed, 13 insertions, 7 deletions
diff --git a/modules/calendar-sync.el b/modules/calendar-sync.el index 15953ba1..06b5531c 100644 --- a/modules/calendar-sync.el +++ b/modules/calendar-sync.el @@ -278,11 +278,14 @@ Monday = 1, Sunday = 7." (defun calendar-sync--add-days (date days) "Add DAYS to DATE (year month day). -Returns new (year month day)." +Returns new (year month day). +Uses noon internally to avoid DST boundary issues where adding +86400 seconds to midnight can land on the same calendar date +during fall-back transitions." (let* ((year (nth 0 date)) (month (nth 1 date)) (day (nth 2 date)) - (time (encode-time 0 0 0 day month year)) + (time (encode-time 0 0 12 day month year)) (new-time (time-add time (days-to-time days))) (decoded (decode-time new-time))) (list (nth 5 decoded) (nth 4 decoded) (nth 3 decoded)))) @@ -292,11 +295,14 @@ Returns new (year month day)." (defun calendar-sync--split-events (ics-content) "Split ICS-CONTENT into individual VEVENT blocks. Returns list of strings, each containing one VEVENT block." - (let ((events '()) - (start 0)) - (while (string-match "BEGIN:VEVENT\\(.\\|\n\\)*?END:VEVENT" ics-content start) - (push (match-string 0 ics-content) events) - (setq start (match-end 0))) + (let ((events '())) + (with-temp-buffer + (insert ics-content) + (goto-char (point-min)) + (while (search-forward "BEGIN:VEVENT" nil t) + (let ((start (match-beginning 0))) + (when (search-forward "END:VEVENT" nil t) + (push (buffer-substring-no-properties start (point)) events))))) (nreverse events))) (defun calendar-sync--get-property (event property) |
