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)))))))