On 10/19/07, Ruby Quiz <james / grayproductions.net> wrote: > by Brian Candler > > Write a Ruby class which can tell you whether the current time (or any given > time) is within a particular "time window". Time windows are defined by strings > in the following format: > > # 0700-0900 # every day between these times > # Sat Sun # all day Sat and Sun, no other times > # Sat Sun 0700-0900 # 0700-0900 on Sat and Sun only > # Mon-Fri 0700-0900 # 0700-0900 on Monday to Friday only > # Mon-Fri 0700-0900; Sat Sun # ditto plus all day Sat and Sun > # Fri-Mon 0700-0900 # 0700-0900 on Fri Sat Sun Mon > # Sat 0700-0800; Sun 0800-0900 # 0700-0800 on Sat, plus 0800-0900 on Sun > > Time ranges should exclude the upper bound, i.e. 0700-0900 is 07:00:00 to > 08:59:59. An empty time window means "all times everyday". Here are some test > cases to make it clearer: Hi, This is my solution: nothing spectacular or too clever. The idea was to convert every part of the window (everything between ";") into a class that knows how to parse the ranges. That class (TimeRange) converts the part into an array of day_of_week ranges and an array of hour ranges. To include a time, this window needs to match at least one day_of_week and at least one hour range. The time window, then, has an array of those TimeRange objects, and tries to find at least one that matches. One interesting thing is that I convert every time definition into a range, even the ones with just one element, so I can use Range#include? across all time ranges. require 'time' class TimeRange def initialize(s) @day_of_week = [] @hour = [] s.strip.split(" ").each do |range| if (match = range.match(/(\d{4})-(\d{4})/)) @hour << (match[1].to_i...match[2].to_i) elsif (match = range.match(/([a-zA-Z]{3})-([a-zA-Z]{3})/)) first = Time::RFC2822_DAY_NAME.index(match[1]) second = Time::RFC2822_DAY_NAME.index(match[2]) if (first < second) @day_of_week << (first..second) else @day_of_week << (first..(Time::RFC2822_DAY_NAME.size-1)) @day_of_week << (0..second) end else @day_of_week << (Time::RFC2822_DAY_NAME.index(range)..Time::RFC2822_DAY_NAME.index(range)) end end end def include?(time) dow = time.wday hour = time.strftime("%H%M").to_i any?(@day_of_week, dow) and any?(@hour, hour) end def any?(enum, value) return true if enum.empty? enum.any?{|x| x.include?(value)} end end class TimeWindow def initialize(s) @ranges = [] s.split(";").each do |part| @ranges << TimeRange.new(part) end end def include?(time) return true if @ranges.empty? @ranges.any? {|x| x.include?(time)} end end Kind regards, Jesus.