oinak
2/8/2014 - 11:46 PM

available.rb

#!/bin/env ruby

class Time
  Days = Day = 24 * 60 * 60
  FixHolidays = Hash.new([]).merge(1 => [1,6], 5 => [1], 10 => [12], 12 => [25])

  def self.holidays
    @@holidays ||= Hash.new(Hash.new([])) # Year Specific holidays { 2013 => { 1 => [7,8]} }
  end

  # Add a year spefic holiday: Time.add_holiday 2014,2,10
  def self.add_holiday(hyear, hmonth, hday)
    holidays[hyear][hmonth] |= [hday]
  end

  def holiday?
    FixHolidays[month].include?(day) || Time.holidays[year][month].include?(day)
  end

  def weekend?
    saturday? || sunday? # wday > 5
  end

  # If it’s a weekend, the date is unavailable.
  # If it’s a holiday, the date is unavailable.
  def available?
    !weekend? && !holiday? && !today?
  end

  def late?
    hour >= 13
  end

  def today?
    (self - Time.now).abs <= 1 * Day
  end

  def self.available_after_r(other, candidate = nil, found = 0)
    candidate ||= other
    needed = (other.late? ? 2 : 1 ) # If it’s after 1pm, take 2nd available
    found += 1 if candidate.available?
    return candidate if found == needed
    available_after_r(other, candidate + 1*Day)
  end

  def self.available_after(other)
    candidate = other
    needed = (other.late? ? 2 : 1 ) # If it’s after 1pm, take 2nd available
    found = 0
    until found == needed
      candidate += 1 * Day
      found += 1 if candidate.available?
    end
    candidate
  end
end


if $0 == __FILE__

  require 'benchmark'

  now = Time.now
  n = 100_000

  Benchmark.bm(10) do |b|
    b.report("Iteration") { n.times{ Time.available_after(now)} }
    b.report("Recursion") { n.times{ Time.available_after_r(now) }}
  end

  # $ ruby avail.rb
  #                  user     system      total        real
  # Iteration    1.320000   0.140000   1.460000 (  1.456945)
  # Recursion    1.420000   0.160000   1.580000 (  1.576072)

end