Function: diary-icalendar-float-sexp-to-recurrence
diary-icalendar-float-sexp-to-recurrence is a byte-compiled function
defined in diary-icalendar.el.gz.
Signature
(diary-icalendar-float-sexp-to-recurrence SEXP)
Documentation
Convert diary-float SEXP to icalendar-dtstart and icalendar-rrule.
Returns a pair of nodes (START RRULE).
Source Code
;; Defined in /usr/src/emacs/lisp/calendar/diary-icalendar.el.gz
(defun di:float-sexp-to-recurrence (sexp)
"Convert `diary-float' SEXP to `icalendar-dtstart' and `icalendar-rrule'.
Returns a pair of nodes (START RRULE)."
(let* ((month-exp (nth 1 sexp))
(months (cond ((eq month-exp t) nil) ; don't add a BYMONTH clause
((integerp month-exp) (list month-exp))
((and (listp month-exp) (eq 'quote (car month-exp)))
(eval month-exp nil)) ; unquote a literal list of ints
(t month-exp)))
(_ (unless (seq-every-p #'integerp months)
(di:signal-export-error
(format "Malformed month(s) in `diary-float' S-expression:\n%s"
sexp))))
(dow (nth 2 sexp))
(n (nth 3 sexp))
(day (or (nth 4 sexp)
(if (< 0 n) 1
'last))) ; = "last day of the month" for any month
;; Calculate the offset within the month from day, n:
(offset
(cond ((eq day 'last) n)
((and (< 0 day) (< 0 n))
;; In this case, to get the offset relative to
;; the start of the month, we need to add to n
;; the number of weeks in the month before day:
;; e.g. if day = 8, n = 2, then we are looking
;; for the second DOW after the 8th of the
;; month, which is the 3rd DOW after the 1st of
;; the month
(+ n (/ (1- day) 7)))
((and (< 0 day) (< n 0) (< day (* 7 (abs n))))
;; In this case, we need to cross into the
;; previous month and adjust the offset
;; accordingly to reflect the correct number of
;; weeks before the end of the month.
;; e.g. if day = 15, n = -3, we're looking for the
;; 3rd DOW before the 15th of the month,
;; which is the 1st DOW "before" the end of the
;; previous month (where "before" is inclusive,
;; e.g offset = -1 will work when DOW is the last
;; day of the month)
(when months
(setq months
(sort
:in-place t
(mapcar
(lambda (m) (if (eql m 1) 12 (1- m)))
months))))
(+ n (/ (1- day) 7)))))
(rrule (delq nil
`((FREQ MONTHLY)
,(when months
(list 'BYMONTH months))
(BYDAY ((,dow . ,offset))))))
(dtstart
(calendar-nth-named-day n dow
(if months (apply #'min months) 1)
di:recurring-start-year
(unless (eq day 'last) day))))
;; if at this point we have an offset which could put us outside the
;; month boundaries, warn the user that this may not be supported:
(when (< 4 (abs offset))
(ical:warn
(format
"`diary-float' with large N=%d may not be supported on other systems" n)))
(list (ical:make-property ical:dtstart dtstart
(ical:valuetypeparam 'ical:date))
(ical:make-property ical:rrule rrule))))