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 more about that here: http://martinfowler.com/apsupp/recurring.pdf 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)