Function: icalendar-recur-refine-bymonthday

icalendar-recur-refine-bymonthday is a byte-compiled function defined in icalendar-recur.el.gz.

Signature

(icalendar-recur-refine-bymonthday INTERVAL MONTHDAYS &optional VTIMEZONE)

Documentation

Resolve INTERVAL into a list of subintervals matching MONTHDAYS.

MONTHDAYS should be a list of values from a recurrence rule's BYMONTHDAY=... clause; see icalendar-recur for the possible values.

Source Code

;; Defined in /usr/src/emacs/lisp/calendar/icalendar-recur.el.gz
(defun icr:refine-bymonthday (interval monthdays &optional vtimezone)
  "Resolve INTERVAL into a list of subintervals matching MONTHDAYS.

MONTHDAYS should be a list of values from a recurrence rule's
BYMONTHDAY=... clause; see `icalendar-recur' for the possible values."
  (let* ((sorted-mdays (sort monthdays
                             :key (lambda (a) (if (< 0 a) a (+ 31 a)))))
         (interval-start (icr:interval-low interval))
         (curr-dt interval-start)
         (interval-end (icr:interval-high interval))
         (subintervals nil))
    (while curr-dt
      ;; For each month in the interval...
      (dolist (m sorted-mdays)
        ;; ...the subinterval is one day long on the given monthday
        (let* ((month (ical:date/time-month curr-dt))
               (year (ical:date/time-year curr-dt))
               (monthday (if (< 0 m) m
                           (+ m 1 (calendar-last-day-of-month month year))))
               (low (ical:date-time-variant curr-dt :day monthday
                                            :hour 0 :minute 0 :second 0
                                            :tz vtimezone))
               (high (ical:date/time-add low :day 1 vtimezone)))

          (ignore-errors ; ignore invalid dates, e.g. 2025-02-29
            ;; Clip subinterval, as above
            (when (ical:date/time< low interval-start)
              (setq low interval-start))
            (when (ical:date/time< interval-end high)
              (setq high interval-end))
            (when (and (ical:date/time<= interval-start low)
                       (ical:date/time< low high)
                       (ical:date/time<= high interval-end))
              (push (icr:make-interval low high) subintervals)))))
      (setq curr-dt (ical:date/time-add curr-dt :month 1 vtimezone))
      (when (ical:date-time<= interval-end curr-dt)
        ;; we're done:
        (setq curr-dt nil)))
    (nreverse subintervals)))