From: Geoff Youngs Date: 2004-03-18T19:46:30+09:00 Subject: Re: Thinking about a date-matching algorithm... On 2004.03.18 06:40, Hal Fulton wrote: > 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? Not sure if this is the sort of thing you're looking for, but I would probably start by reducing the task description to a set of rules which need to be fulfilled (and which can be simply matched as true or false) For each task you'd store when it was first run etc, and to work out whether a task was due for a particular day by comparing the rules with hypothetical values for that day. e.g. Every Monday wday = 1 Every day # Always match Every second and fourth Friday (wday = 5) & (weekday_occurrence_in_month = 2 | weekday_occurrence_in_month = 4) Every ten days firstrun_days_ago % 10 # '%' true if lhs multiple of rhs The main advantage (IMHO) of using a dialect like this is that if it is understood by your ruby program, you've got a reasonable chance of being able to convert it to both relatively trust-able ruby code and (potentially) a more humanly readable description. Which could be stored in, for example, an XML file: ... (And it would probably be best to allow nesting of tags so that you can combine match="all" and match="any". The rules and match tags could map fairly directly to classes which could then check their rule or list of rules recursively. And all you'd then need to do is pass a hash of values for the particular day to the outermost rules object. e.g. date= Date.today firstrun = Date.parse '2003-02-01' target_date = {'wday'=>date.wday, 'firstrun'=>firstrun.to_s, 'first_run_days_ago'=>(date - firstrun).to_i, 'week'=>date.week, ... } if task.rules.match?(target_date) ... OK end (Although using a block passed to Hash.new should probably be faster than calculating all possible values every time) I've got code which does something similar, but it's not specifically targeted at date matching - drop me a line if it would be of interest. HTH, Geoff. -- I'm sorry if I photographed your pet pig, but catholics blow up digital cameras.