Skip to content

Instantly share code, notes, and snippets.

@colincasey
Created May 26, 2010 13:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save colincasey/2ab2ac2625ad8d3c9f2d to your computer and use it in GitHub Desktop.
Save colincasey/2ab2ac2625ad8d3c9f2d to your computer and use it in GitHub Desktop.
Solution to RPCFN Challenge #10
# encoding: utf-8
require 'time'
class BusinessHours
CLOSED = []
def initialize(default_open_hour, default_close_hour)
@open_close = {}
@default_open_close = [default_open_hour, default_close_hour]
end
def update(day, open, close)
@open_close[day] = [open, close]
end
def closed(*days)
days.each { |day| @open_close[day] = CLOSED }
end
def calculate_deadline(time_to_complete, start_time)
current_time = Time.parse(start_time)
current_time += time_until_open(current_time)
while true
work_time = work_time(current_time)
if time_to_complete < work_time
current_time += time_to_complete
break
else
current_time += work_time + time_to_next_open(current_time)
time_to_complete -= work_time
end
end
current_time
end
private
# returns the open and close times for the specified date or an empty array if closed on that date
def open_close_times(date)
open_close = @open_close[as_string(date)] || @open_close[as_sym(date)] || @default_open_close
open_close.collect { |h| Time.parse("#{as_string(date)} #{h}") }
end
# the length of time available during a specified day to do work
# e.g., there are 6 hours available if we open at 9:00 AM, close at 3:00 PM, and the item was dropped off at 9:00 AM
# there are 5 hours available if we open at 9:00 AM, close at 3:00 PM, and the item was dropped off at 10:00 AM
def work_time(date)
open, closed = open_close_times(date)
closed - open - time_already_open(date)
end
# the length of time from the specified time until we open
# e.g., if the specified time is 6:00 AM and we open at 8:30 AM, then the time until open is 2 hours and 30 minutes
def time_until_open(date)
open = open_close_times(date).first
open - date > 0 ? open - date : 0
end
# the length of time from when we opened to the specified time
# e.g., if we opened at 9:00 AM and the time specified is 9:30 AM, then the time already open is 30 minutes
def time_already_open(date)
open = open_close_times(date).first
date - open > 0 ? date - open : 0
end
# the length of time from the close of the working day on the specified date until the next opening
# e.g., if we close at 5:00 PM on May 26 and don't open again until 9:00 AM on May 28, then the time to next open is 40 hours
def time_to_next_open(date)
closed_at = open_close_times(date).last
date = next_day(date)
while open_close_times(date) == CLOSED
date = next_day(date)
end
open_at = open_close_times(date).first
open_at - closed_at
end
# the date in our string format: e.g., Monday April 05, 2010 9:00 AM = Apr 05, 2010
def as_string(date)
date.strftime("%b %d, %Y")
end
# the date in our short format: e.g., Monday April 05, 2010 9:00 AM = :mon
def as_sym(date)
date.strftime("%a").downcase.to_sym
end
# advance the specified date by 24 hours
def next_day(date)
date + (60 * 60 * 24)
end
end
# encoding: utf-8
require 'test/unit'
require 'business_hours'
class BusinessHoursTest < Test::Unit::TestCase
def setup
@hours = BusinessHours.new("9:00 AM", "3:00 PM")
@hours.update :fri, "10:00 AM", "5:00 PM"
@hours.update "Dec 24, 2010", "8:00 AM", "1:00 PM"
@hours.closed :sun, :wed, "Dec 25, 2010"
end
def test_case_1
assert_equal Time.parse("Mon Jun 07 11:10:00 2010"), @hours.calculate_deadline(2*60*60, "Jun 7, 2010 9:10 AM")
end
def test_case_2
assert_equal Time.parse("Thu Jun 10 09:03:00 2010"), @hours.calculate_deadline(15*60, "Jun 8, 2010 2:48 PM")
end
def test_case_3
assert_equal Time.parse("Mon Dec 27 11:00:00 2010"), @hours.calculate_deadline(7*60*60, "Dec 24, 2010 6:45 AM")
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment