9e62875c

By: Tom Sydney Kerckhove <syd@cs-syd.eu>

ical-recurrence: ignore instances whose local time does not exist

@
Recurrence rules may generate recurrence instances with an invalid
date (e.g., February 30) or nonexistent local time (e.g., 1:30 AM
on a day where the local time is moved forward by an hour at 1:00
AM).  Such recurrence instances MUST be ignored and MUST NOT be
counted as part of the recurrence set.
@

@
the BYxxx rule parts
are applied to the current set of evaluated occurrences in the
following order: [...] and BYSETPOS; then COUNT and UNTIL are
evaluated.
@

An hour that a transition skips has no instant that maps to it, so
resolving a local time inside it lands on an instant that belongs to a
different local time: 02:30 on the 27th of March 2022 in Zurich came out
as 01:30.  A local time exists exactly when resolving and unresolving it
gives it back, so that round trip is the test.

The filtering happens before COUNT and UNTIL rather than after, because
an ignored instance never becomes an occurrence, and those two count
occurrences and are evaluated last.  An invalid date is already dropped
that early by the day generation itself, so both halves of that one
requirement now behave the same way, which is what leapdays.ics has
always relied on.

The predicate is a plain function rather than an action in R so that the
list of occurrences stays lazy and a COUNT still stops as soon as it has
enough, instead of generating everything up to the limit and filtering
afterwards.  DTSTART is not subject to it: the rule did not generate it,
and it defines the first instance whatever it says.