
A. The "secondly", "minutely", and "hourly" recurrences, and the "bysecond",
        "byminute", and "byhour" rules, are eliminated.
B. The "count" and "bysetpos" rules are eliminated.
C. The duration of the event ("duration" or "dtend - dtstart") must be
        less than 24 hours.

Here is the algorithm:
1.  Compute the time of the call, in the timezone of the time switch.
    (No step after this needs to consider time zones -- all calculations
    are done using continuously-running standard Gregorian time.)

2.  If the call time is earlier than dtstart, fail NOMATCH.

3.  If the call time is less than 'duration' after dtstart, succeed MATCH.

4.  Determine the smallest unit specified in a "by*" rule or by the "freq".
    Call this the Minimum Unit.  Determine the previous instant (before
    the call time) when all the time units smaller than the minimum unit
    are the same as those of DTStart.  (For all minimum units, the
    time-of-day must be the same as dtstart.  If the minimum unit is a week,
    the day-of-the-week must be the same as dtstart.  If the minimum unit is
    a month, the day-of-the-month must be the same as dtstart.  If the
    minimum unit is a year, the month and day-of-month must both be the same
    as dtstart.  (Note that this means it may be necessary to roll back more
    than one minimum unit -- if the minimum unit is a month, then some
    months do not have a 31st (or 30th or 29th) day; if the minimum unit is
    a year, then some years do not have a February 29th.  In the Gregorian
    calendar, it is never necessary to roll back more than two months, or
    eight years (four years between 1901 and 2099).)

    Call this instant the Candidate Start Time.

5.  If the time between the candidate start time and the call time is more
    than the duration, fail NOMATCH.

6.  If the candidate start time is later than the 'until' parameter of the
    recurrence, fail NOMATCH.

7.  Call the unit of the 'freq' parameter of the recurrence the Frequency
    Unit.  Determine the frequency unit enclosing the Candidate Start Time,
    and that enclosing DTStart.  Calculate the number of frequency units
    that have passed between these two times.  If this is not a multiple
    of the "interval" parameter, fail NOMATCH.

8.  For every by* rule, confirm that the candidate start time matches one
    of the options specified by that by* rule.  If not, fail NOMATCH.

9.  Succeed MATCH.


Some notes on this algorithm:

The justifications for each of the eliminations above are as follows.

A.  When sub-day-resolution rules are present, issues of daylight-savings
        transitions come into play.  The number of, e.g., "nine hour"
        intervals since a given time isn't easily computable from a
        broken-down local time if a DST transition has occured in between.
        Since sub-day-resolution rules don't seem especially useful for
        recurring events anyway, we can avoid consideration of these
        issues by eliminating them.

B.  Barring very clever (and complex) algorithms that escape me, "count" and
        "bysetpos" rules both require that a set of recurrences be fully
        enumerated for them to be correctly resolved.

C.  Durations longer than the minimum unit can result in multiple candidate
        start times being possible for a given call time.  The simplest way
        to resolve this is by forcing durations to be less than 24
        hours, while eliminating the sub-day frequencies and rules.  The
        algorithm would still work with just the weaker condition (duration
        < min unit), though this would be much harder to explain.


Notes on importing from full iCal:

In my experience, no actual calendaring implementations present a user
interface for creating sub-day-resolution recurrences.  Very few allow
appointments longer than 24 hours.

Converting from 'count' to 'until' parameters, for a client which must
enumerate the event listings anyway, is trivial.

'bysetpos', 'rdate', 'exrule', and 'exdate' can all be handled by
converting a single full iCal RRULE into multiple time-switches, linked
with sub's to the same output.
