Hey Jim,
Is ECal going to be a public project? Are you welcoming acolytes? Runt works
just fine (for an 0.0.6 release), but I’ve created it mostly as a way to
learn Ruby; I’d gladly merge/scrap it for an opportunity to learn from a
more experienced Rubyist.
Matt
···
-----Original Message-----
From: Jim Weirich [mailto:jim@weirichhouse.org]
Sent: Thursday, March 18, 2004 12:49 PM
To: ruby-talk@ruby-lang.org
Subject: Re: Thinking about a date-matching algorithm…
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)