7c1d803a

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

Replaces #11, which GitHub closed automatically when #23 was merged and its
base branch deleted. Same two commits, now based on `master`.

An hour that a daylight saving transition skips has no instant that maps to
it, so resolving a local time inside it lands on an instant belonging to a
different local time. Zurich skips 02:00–03:00 on the 27th of March 2022, and
`02:30` on that day came out as `01:30`.

```
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.
```

## Commits

1. **red** — the gap test, a `COUNT` test, and a guard for the ambiguous side. 261 passing / 2 failing.
2. **green** — the fix. 263 passing / 0 failing.

## Filtering happens before COUNT

```
[...] and BYSETPOS; then COUNT and UNTIL are evaluated.
```

An ignored instance never becomes an occurrence, and `COUNT` counts
occurrences and is evaluated last, so a skipped instance must not use up one
of the count. `leapdays.ics` has always relied on that for the invalid-date
half of the same sentence, so both halves now behave alike. There is a test
pinning it: `FREQ=DAILY;COUNT=4` across the transition yields four instances,
not three.

## Notes

- The predicate is a plain function rather than an action in `R`, which keeps
  the occurrence list lazy so a `COUNT` still stops as soon as it has enough
  instead of generating everything up to the limit and filtering afterwards.
- Threading it took one new parameter on `recurRecurrenceRuleDateTimeStarts`
  (single caller) and an internal `recurRecurrenceRuleLocalTimesWhere`, with
  `recurRecurrenceRuleLocalTimes` kept as a wrapper, so no frequency test
  changed.
- `DTSTART` is exempt: the rule did not generate it, and it defines the first
  instance whatever it says.
- The ambiguous side of a transition is covered by a test that passes before
  and after, so this fix cannot quietly change it.

Suite timing

Time to Start Worker time Duration Time to finish Idle
Config 0s 1s 1s 1s 0s
Eval 1s 10s 10s 12s 0s
Build 11s 0s 0s 11s 0s
Suite 0s 12s 12s 12s 0s

Timeline

0s10s