diff --git a/config.el b/config.el index 319d692..b4af14f 100644 --- a/config.el +++ b/config.el @@ -324,6 +324,11 @@ "* %?\n%(my/calfw-capture-timestamp)\n" :empty-lines 1)))) +;; Ensure ox-icalendar exports active timestamps with times correctly +(after! ox-icalendar + (setq org-icalendar-with-timestamps 'active + org-icalendar-timezone "Europe/Prague")) + ;;; ============================================================ ;;; ORG MODE — AGENDA @@ -1593,18 +1598,55 @@ Skip for beamer exports — beamer uses adjustbox on plain tabular." :demand t :config ;; org-capture integration: "a" to add event on selected date - ;; Prompts for time range; empty = all-day event + ;; Prompts for start/end time; empty = all-day event + ;; Uses active timestamp with time range for timed events, + ;; or date-range (-->--) for multi-day events. (defun my/calfw-capture-timestamp () - "Build org timestamp for selected calfw date with optional time prompt." + "Build org timestamp for selected calfw date with optional time prompt. +Formats matching what org-caldav/ox-icalendar export correctly: + - All-day single: <2026-02-26 Thu> + - Timed single day: <2026-02-26 Thu 14:00-15:30> + - All-day multi: <2026-02-26 Thu>--<2026-02-28 Sat> + - Timed multi-day: <2026-02-26 Thu 15:00>--<2026-02-28 Sat 22:00>" (let* ((date (calfw-cursor-to-nearest-date)) (y (calendar-extract-year date)) (m (calendar-extract-month date)) (d (calendar-extract-day date)) (dow (calendar-day-name (encode-time 0 0 0 d m y) nil t)) - (time (read-string "Time (e.g. 14:00-15:30, empty=all-day): "))) - (if (string-empty-p time) - (format "<%04d-%02d-%02d %s>" y m d dow) - (format "<%04d-%02d-%02d %s %s>" y m d dow time)))) + (start-time (read-string "Start time (HH:MM, empty=all-day): ")) + (end-input (unless (string-empty-p start-time) + (read-string "End time or end date (HH:MM / YYYY-MM-DD / YYYY-MM-DD HH:MM, empty=same day open): ")))) + (cond + ;; All-day event (no time given) + ((string-empty-p start-time) + (let ((end-date (read-string "End date for multi-day (YYYY-MM-DD, empty=single day): "))) + (if (string-empty-p end-date) + (format "<%04d-%02d-%02d %s>" y m d dow) + (let* ((parsed (parse-time-string (concat end-date " 00:00"))) + (ed (nth 3 parsed)) (em (nth 4 parsed)) (ey (nth 5 parsed)) + (edow (calendar-day-name (encode-time 0 0 0 ed em ey) nil t))) + (format "<%04d-%02d-%02d %s>--<%04d-%02d-%02d %s>" y m d dow ey em ed edow))))) + ;; Timed event - check if end contains a date (multi-day) + ((and end-input (not (string-empty-p end-input)) + (string-match "^[0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}" end-input)) + ;; Multi-day with times + (let* ((end-time-part (if (string-match " \\([0-9]\\{2\\}:[0-9]\\{2\\}\\)" end-input) + (match-string 1 end-input) "")) + (end-date-part (substring end-input 0 10)) + (parsed (parse-time-string (concat end-date-part " 00:00"))) + (ed (nth 3 parsed)) (em (nth 4 parsed)) (ey (nth 5 parsed)) + (edow (calendar-day-name (encode-time 0 0 0 ed em ey) nil t))) + (if (string-empty-p end-time-part) + (format "<%04d-%02d-%02d %s %s>--<%04d-%02d-%02d %s>" + y m d dow start-time ey em ed edow) + (format "<%04d-%02d-%02d %s %s>--<%04d-%02d-%02d %s %s>" + y m d dow start-time ey em ed edow end-time-part)))) + ;; Same-day timed event with end time (HH:MM) + ((and end-input (not (string-empty-p end-input))) + (format "<%04d-%02d-%02d %s %s-%s>" y m d dow start-time end-input)) + ;; Same-day timed event, no end time + (t + (format "<%04d-%02d-%02d %s %s>" y m d dow start-time))))) (setq calfw-org-capture-template '("c" "Calendar event" entry