Friday, November 30, 2007

Ruby, Schedule, Reoccurrence, Date, Range, Runt

Almost all of the application that I worked with has something to do with dates and time, and most of those has something to do with scheduling as well, say SoccerMap, where the user can schedule a reoccurring soccer game on google map.

But after all of the research that I have done for how to solve this problem from google, it generally comes down to 2 routes. First is to compute them, and the second is to pre-populate them in the database or file, and perform selects from it.

While the first solution seems to be efficient on the data storage, it might require more time and cpu to crank out the right occurrence dates. The second one seems to be much faster, as everything is almost a lookup away, it will hit the wall once user wants to know what happens in year 3000 ;-)

After lots of mind wrestling and discussion with other programmers, I decided to find a way to compute the occurrence either with a simple algorithm or a library that does it already.

To my surprise, even a problem as universal as this didn’t have a lot of good implementations in various languages. It’s usually provided through a module or external library, and there aren’t many good answers that surfaces google.

Luckily, I found one for the language that I prefer, runt for ruby ;-)

Following is the code to get a series of reoccurring dates from a schedule.

require 'runt'
require 'date'

include Runt
include DPrecision

last_thursday = DIMonth.new(Last_of,Thursday)
august = REYear.new(8)
expr = last_thursday & august

>> (Date.new(2004,1,1)..Date.new(2004,12,31)).select {|d| expr.include? d }
=> [Thu, 26 Aug 2004]
>> (Date.new(2004,1,1)..Date.new(2004,12,31)).select {|d| last_thursday.include? d }
=> [Thu, 29 Jan 2004, Thu, 26 Feb 2004, Thu, 25 Mar 2004, Thu, 29 Apr 2004, Thu, 27 May 2004, Thu, 24 Jun 2004, Thu, 29 Jul 2004, Thu, 26 Aug 2004, Thu, 30 Sep 2004, Thu, 28 Oct 2004, Thu, 25 Nov 2004, Thu, 30 Dec 2004]
References: