Skip to content

Instantly share code, notes, and snippets.

@benoitr
Forked from ryanb/business_hours.rb
Last active August 29, 2015 14:07
Show Gist options
  • Save benoitr/4eb2915f53a0ec4b40b5 to your computer and use it in GitHub Desktop.
Save benoitr/4eb2915f53a0ec4b40b5 to your computer and use it in GitHub Desktop.
require "time"
require "date"
class Date
def to_time
Time.local(year, month, day)
end
end
class Time
def to_date
Date.new(year, month, day)
end
end
class BusinessHours
def initialize(opening, closing)
@schedule = { :default => [opening, closing] }
end
def update(day, opening, closing)
key = day.kind_of?(Symbol) ? Date.parse(day.to_s).wday : Date.parse(day)
@schedule[key] = [opening, closing]
end
def closed(*days)
days.each { |day| update(day, "0:00", "0:00") }
end
def calculate_deadline(interval, start_time)
Deadline.new(@schedule, interval, Time.parse(start_time)).calculate
end
class Deadline
def initialize(*args)
@schedule, @remaining, @current_time = *args
end
def calculate
increment_day while after_today?
current_or_opening_time + @remaining
end
private
def after_today?
current_or_opening_time + @remaining > closing_time
end
def increment_day
@remaining -= closing_time - current_or_opening_time if @current_time < closing_time
@current_time = @current_time.to_date.next.to_time
end
def current_or_opening_time
[@current_time, opening_time].max
end
def opening_time
Time.parse(current_hours.first, @current_time)
end
def closing_time
Time.parse(current_hours.last, @current_time)
end
def current_hours
@schedule[@current_time.to_date] || @schedule[@current_time.wday] || @schedule[:default]
end
end
end
require "test/unit"
require File.dirname(__FILE__) + '/business_hours'
class BusinessHoursTest < Test::Unit::TestCase
def setup
@hours = BusinessHours.new("8:00 AM", "5:00 PM")
end
def test_within_working_hours
assert_equal Time.parse("Dec 21, 2009 3:05 PM"), @hours.calculate_deadline(5*60, "Dec 21, 2009 3:00 PM")
end
def test_start_at_opening_time
assert_equal Time.parse("Dec 21, 2009 8:05 AM"), @hours.calculate_deadline(5*60, "Dec 21, 2009 7:27 AM")
end
def test_start_next_day_when_after_closing_time
assert_equal Time.parse("Dec 21, 2009 8:05 AM"), @hours.calculate_deadline(5*60, "Dec 20, 2009 6:37 PM")
end
def test_carry_over_remaining_time_onto_next_day
assert_equal Time.parse("Dec 22, 2009 8:02 AM"), @hours.calculate_deadline(5*60, "Dec 21, 2009 4:57 PM")
end
def test_skip_full_day
assert_equal Time.parse("Dec 23, 2009 8:57 AM"), @hours.calculate_deadline(10*60*60, "Dec 21, 2009 4:57 PM")
end
def test_skip_current_day_before_opening
assert_equal Time.parse("Dec 22, 2009 9:00 AM"), @hours.calculate_deadline(10*60*60, "Dec 21, 2009 7:57 AM")
end
def test_update_week_day_hours
@hours.update :mon, "8:00 AM", "3:00 PM"
@hours.update :tue, "9:00 AM", "5:00 PM"
assert_equal Time.parse("Dec 22, 2009 9:02 AM"), @hours.calculate_deadline(5*60, "Dec 21, 2009 2:57 PM")
end
def test_skip_closed_days
@hours.closed :sat, :sun
assert_equal Time.parse("Dec 21, 2009 8:02 AM"), @hours.calculate_deadline(5*60, "Dec 18, 2009 4:57 PM")
end
def test_change_hours_for_specific_dates
@hours.update "Dec 24, 2009", "8:00 AM", "3:00 PM"
@hours.closed :sat, :sun, "Dec 25, 2009"
assert_equal Time.parse("Dec 28, 2009 8:02 AM"), @hours.calculate_deadline(5*60, "Dec 24, 2009 2:57 PM")
assert_equal Time.parse("Dec 17, 2009 3:02 PM"), @hours.calculate_deadline(5*60, "Dec 17, 2009 2:57 PM")
end
def test_start_on_closed_days
@hours.closed :tue, "Dec 25, 2009"
assert_equal Time.parse("Dec 23, 2009 8:05 AM"), @hours.calculate_deadline(5*60, "Dec 22, 2009 4:57 PM")
assert_equal Time.parse("Dec 26, 2009 8:05 AM"), @hours.calculate_deadline(5*60, "Dec 25, 2009 4:57 PM")
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment