Thinking about a date-matching algorithm

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)

mlipper@US-ABP.com wrote:

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.

ECal is actually a learning project for our XP Users group. Once a
month we get together and work on it for a few hours, practicing
pairing, TDD, and writing acceptance tests.

If you wish to work on ECal … feel free to show up at Children’s
Hospital in Cincinnati and do some pairing. We meet the first Tuesday
of the month. :slight_smile: (Link: http://objectwind.com/xp-cinci/)

Seriously, since it is a learning project, we are not looking for
independent, remote developers. However, if you wish to take it and run
with it independently … feel free. Let me warn you however, working
on it only a few hours every month doesn’t move the project along very
fast. So there is very little there at this time. I will populate the
RubyForge CVS tree soon (before the next XP-Cincy meeting for sure).

BTW, folks might be interested in noting that the group is made up of
mostly Java programmers. At any given meeting there will be between 4
to 6 pairs of Java programmers and 1 pair of Ruby programmers. Yet, the
Ruby version of ECal is keeping pace with the Java version. Part of
that is due to the nature of Ruby, and part is the fact that with fewer
programmers, we don’t thrash between alternatives as much as the larger
Java group.

Thanks for your interest.

···


– 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)