Function: icalendar-recur-recurrences-in-interval
icalendar-recur-recurrences-in-interval is a byte-compiled function
defined in icalendar-recur.el.gz.
Signature
(icalendar-recur-recurrences-in-interval INTERVAL COMPONENT &optional VTIMEZONE NMAX)
Documentation
Return a list of the recurrences of COMPONENT in INTERVAL.
INTERVAL should be an interval [LOW HIGH NEXT] of date-times which bound a
single recurrence interval, as returned e.g. by
icalendar-recur-find-interval. (To find the recurrences in an
arbitrary window of time, rather than between interval boundaries, see
icalendar-recur-recurrences-in-window.)
COMPONENT should be an iCalendar component node representing a recurring
event: it should contain at least an icalendar-dtstart and either an
icalendar-rrule or icalendar-rdate property.
If specified, VTIMEZONE should be an icalendar-vtimezone component.
In this case, the dates and times of recurrences will be computed with
UTC offsets local to that time zone.
If specified, NMAX should be a positive integer containing a maximum
number of recurrences to return from this interval. In this case, if the
interval contains more than NMAX recurrences, only the first NMAX
recurrences will be returned; otherwise all recurrences in the interval
are returned. (The NMAX argument mainly exists to support recurrence
rules with a COUNT clause; see icalendar-recur-recurrences-to-count.)
The returned list is a list of icalendar-date or icalendar-date-time
values representing the start times of recurrences. Note that any
values of type icalendar-period in COMPONENT's icalendar-rdate
property (or properties) will NOT be included in the list; it is the
callee's responsibility to handle any such values separately.
The computed recurrences for INTERVAL are cached in COMPONENT and retrieved on subsequent calls with the same arguments.
Source Code
;; Defined in /usr/src/emacs/lisp/calendar/icalendar-recur.el.gz
;; Calculating recurrences in a given interval or window
;;
;; We can now put all of the above together to compute the set of
;; recurrences in a given interval (`icr:recurrences-in-interval'), and
;; thereby in a given window (`icr:recurences-in-window'); or, if the
;; rule describing the set has a COUNT clause, we can enumerate the
;; recurrences in each interval starting from the beginning of the set
;; (`icr:recurrences-to-count').
(defun icr:recurrences-in-interval (interval component &optional vtimezone nmax)
"Return a list of the recurrences of COMPONENT in INTERVAL.
INTERVAL should be an interval [LOW HIGH NEXT] of date-times which bound a
single recurrence interval, as returned e.g. by
`icalendar-recur-find-interval'. (To find the recurrences in an
arbitrary window of time, rather than between interval boundaries, see
`icalendar-recur-recurrences-in-window'.)
COMPONENT should be an iCalendar component node representing a recurring
event: it should contain at least an `icalendar-dtstart' and either an
`icalendar-rrule' or `icalendar-rdate' property.
If specified, VTIMEZONE should be an `icalendar-vtimezone' component.
In this case, the dates and times of recurrences will be computed with
UTC offsets local to that time zone.
If specified, NMAX should be a positive integer containing a maximum
number of recurrences to return from this interval. In this case, if the
interval contains more than NMAX recurrences, only the first NMAX
recurrences will be returned; otherwise all recurrences in the interval
are returned. (The NMAX argument mainly exists to support recurrence
rules with a COUNT clause; see `icalendar-recur-recurrences-to-count'.)
The returned list is a list of `icalendar-date' or `icalendar-date-time'
values representing the start times of recurrences. Note that any
values of type `icalendar-period' in COMPONENT's `icalendar-rdate'
property (or properties) will NOT be included in the list; it is the
callee's responsibility to handle any such values separately.
The computed recurrences for INTERVAL are cached in COMPONENT and
retrieved on subsequent calls with the same arguments."
(ical:with-component component
((ical:dtstart :value dtstart)
(ical:tzoffsetfrom :value offset-from)
(ical:rrule :value rrule)
(ical:rdate :all rdate-nodes) ;; TODO: these can also be ical:period values
(ical:exdate :all exdate-nodes))
(if (not (or rrule rdate-nodes))
;; No recurrences to calculate, so just return early:
nil
;; Otherwise, calculate recurrences in the interval:
(when (memq (ical:ast-node-type component) '(ical:standard ical:daylight))
;; In time zone observances, set the zone field in dtstart
;; from the TZOFFSETFROM property:
(setq dtstart
(ical:date-time-variant dtstart
:zone offset-from
:dst (not (ical:daylight-component-p
component)))))
(let ((cached (icr:-set-get-interval component interval)))
(cond ((eq cached :none) nil)
(cached cached)
(t
(let* (;; Start by generating all the recurrences matching the
;; BY* clauses except for BYSETPOS:
(subs (icr:refine-from-clauses interval rrule dtstart
vtimezone))
(sub-recs (icr:subintervals-to-recurrences subs dtstart
vtimezone))
;; Apply any BYSETPOS clause to this set:
(keep-indices (ical:rrule-by* 'BYSETPOS rrule))
(pos-recs
(if keep-indices
(icr:bysetpos-filter keep-indices sub-recs)
sub-recs))
;; Remove any recurrences before DTSTART or after UNTIL
;; (both of which are inclusive bounds):
(until (ical:rrule-until rrule))
(until-recs
(seq-filter
(lambda (rec) (and (ical:date/time<= dtstart rec)
(or (not until)
(ical:date/time<= rec until))))
pos-recs))
;; Include any values in the interval from the
;; RDATE property:
(low (icr:interval-low interval))
(high (icr:interval-high interval))
(rdates
(mapcar #'ical:ast-node-value
(apply #'append
(mapcar #'ical:ast-node-value rdate-nodes))))
(interval-rdates
(seq-filter
(lambda (rec)
;; only include ical:date and ical:date-time
;; values from RDATE; callee is responsible
;; for handling ical:period values
(unless (cl-typep rec 'ical:period)
(and (ical:date/time<= low rec)
(ical:date/time< rec high))))
rdates))
(included-recs (append until-recs interval-rdates))
;; Exclude any values from the EXDATE property;
;; this gives us the complete set of recurrences
;; in this interval:
(exdates
(mapcar #'ical:ast-node-value
(apply #'append
(mapcar #'ical:ast-node-value exdate-nodes))))
(all-recs
(if exdates
(seq-filter
(lambda (rec) (not (member rec exdates)))
included-recs)
included-recs))
;; Limit to the first NMAX recurrences if requested.
;; `icr:recurrences-to-count' provides NMAX so as not to
;; store more recurrences in the final interval than the
;; COUNT clause allows:
(nmax-recs
(if nmax (take nmax all-recs)
all-recs)))
;; Store and return the computed recurrences:
(icr:-set-put-interval component interval
(or nmax-recs :none))
nmax-recs)))))))