```Hal Fulton said:
> I did a little swapping of ideas with dblack on this. Now I'm
> opening discussion to anyone interested.
>
> I'm writing a little to-do manager (chiefly for my own use).
>
> I want to allow recurring tasks. Some of these will be simple, like
> "Every Monday." Others will be more complex, like "Every 2nd and 4th
> Friday." Some might not even be based on weeks or months at all, but
> might be like: "Every ten days, no matter what."
>
> There'd also be an option to give advance warning (N days) on each
> event.
>
> So the question becomes: Given a date (typically "today") and a list
> of recurring tasks, how do I determine which ones need to be displayed?

What a timely question!

Our local XP users group is addressing the exact same issue.  We are
developing a schedule program for reserving rooms at Children's Hospital.
We need to deal with issues like "Schedule this room every third monday of
the month".

We decided to use Martin Fowler's Temporal Expressions pattern.  You can

To summarize, you can create arbitrarily complex temporal expressions by
using a small set of primitives (e.g. YearInRange, DayOfMonth) and a
simple set of combining rules (Union, Intersection, Difference).

For example, you can create simple expressions ...

# Match the third Monday of the month
days = TExp::WeekDayInMonth.new(3, TExp::MONDAY)

# Match any date in June thru August (of any year)
range = TExp::RangeEachYear.by_month(6,9)

And combine them into complex expressions ...

# Match any 3rd Monday in June through August
dates = TExp::Union.new(days, range)

# Test against specific days
dates.includes?(Date.new(2004, 6, 21)  # => true
dates.includes?(Date.new(2004, 7, 19)  # => true
dates.includes?(Date.new(2004, 6, 14)  # => false, not 3rd Monday
dates.includes?(Date.new(2004, 5, 24)  # => false, not in Jun-Aug

Does this make sense?  Read the PDF for all the gory details.

And you are in luck.  There are at least two Temporal Expression libraries
in Ruby.  I have one that is part of the ECal project on RubyForge (I
haven't published any files yet tho ... but I can if there is a need).
The other one is Runt (http://runt.rubyforge.org/) by Matthew Lipper,
which is also on RubyForge.

--
-- Jim Weirich     jim / weirichhouse.org    http://onestepback.org
-----------------------------------------------------------------
"Beware of bugs in the above code; I have only proved it correct,
not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)

```