Function: nndiary-last-occurrence
nndiary-last-occurrence is a byte-compiled function defined in
nndiary.el.gz.
Signature
(nndiary-last-occurrence SCHED)
Aliases
nndiary-last-occurence (obsolete since 26.1)
Source Code
;; Defined in /usr/src/emacs/lisp/gnus/nndiary.el.gz
(defun nndiary-last-occurrence (sched)
;; Returns the last occurrence of schedule SCHED as an Emacs time struct, or
;; nil for permanent schedule or errors.
(let ((minute (nndiary-max (nth 0 sched)))
(hour (nndiary-max (nth 1 sched)))
(year (nndiary-max (nth 4 sched)))
(time-zone (or (car (nth 6 sched))
(current-time-zone))))
(when year
(or minute (setq minute 59))
(or hour (setq hour 23))
;; I'll just compute all possible values and test them by decreasing
;; order until one succeeds. This is probably quite rude, but I got
;; bored in finding a good algorithm for doing that ;-)
;; ### FIXME: remove identical entries.
(let ((dom-list (nth 2 sched))
(month-list (sort (nndiary-flatten (nth 3 sched) 1 12) #'>))
(year-list (sort (nndiary-flatten (nth 4 sched) 1971) #'>))
(dow-list (nth 5 sched)))
;; Special case: an asterisk in one of the days specifications means
;; that only the other should be taken into account. If both are
;; unspecified, you would get all possible days in both.
(cond ((null dow-list)
;; this gets all days if dom-list is nil
(setq dom-list (nndiary-flatten dom-list 1 31)))
((null dom-list)
;; this also gets all days if dow-list is nil
(setq dow-list (nndiary-flatten dow-list 0 6)))
(t
(setq dom-list (nndiary-flatten dom-list 1 31))
(setq dow-list (nndiary-flatten dow-list 0 6))))
(or
(catch 'found
(while (setq year (pop year-list))
(let ((months month-list)
month)
(while (setq month (pop months))
;; Now we must merge the Dows with the Doms. To do that, we
;; have to know which day is the 1st one for this month.
;; Maybe there's simpler, but decode-time(encode-time) will
;; give us the answer.
(let ((first (decoded-time-weekday
(decode-time
(encode-time 0 0 0 1 month year
time-zone))))
(max (cond ((= month 2)
(if (date-leap-year-p year) 29 28))
((<= month 7)
(if (evenp month) 30 31))
(t
(if (evenp month) 31 30))))
(doms dom-list)
(dows dow-list)
day days)
;; first, review the doms to see if they are valid.
(while (setq day (pop doms))
(and (<= day max)
(push day days)))
;; second add all possible dows
(while (setq day (pop dows))
;; days start at 1.
(setq day (1+ (- day first)))
(and (< day 0) (setq day (+ 7 day)))
(while (<= day max)
(push day days)
(setq day (+ 7 day))))
;; Finally, if we have some days, they are valid
(when days
(throw 'found
(encode-time 0 minute hour
(apply #'max days)
month year time-zone)))
)))))
;; There's an upper limit, but we didn't find any last occurrence.
;; This means that the schedule is undecidable. This can happen if
;; you happen to say something like "each Feb 31 until 2038".
(progn
(nnheader-report 'nndiary "Undecidable schedule")
nil))
))))