Skip to content

Commit

Permalink
Added support for configuring the work week.
Browse files Browse the repository at this point in the history
  • Loading branch information
glv committed Jan 25, 2012
1 parent c7b8723 commit cb3189d
Show file tree
Hide file tree
Showing 11 changed files with 85 additions and 33 deletions.
22 changes: 12 additions & 10 deletions README.rdoc
Expand Up @@ -69,11 +69,17 @@ I needed this, but taking into account business hours/days and holidays.
BusinessTime::Config.holidays << three_day_weekend
friday_afternoon = Time.parse("July 2nd, 2010, 4:50 pm")
tuesday_morning = 1.business_hour.after(friday_afternoon)

# you can also calculate business duration between two dates
friday = Date.parse("December 24, 2010")

# plus, we can change the work week:
# July 9th in 2010 is a Friday.
BusinessTime::Config.work_week = [:sun, :mon, :tue, :wed, :thu]
thursday_afternoon = Time.parse("July 8th, 2010, 4:50 pm")
sunday_morning = 1.business_hour.after(thursday_afternoon)

# you can also calculate business duration between two dates
friday = Date.parse("December 24, 2010")
monday = Date.parse("December 27, 2010")
friday.business_days_until(monday) #=> 1
friday.business_days_until(monday) #=> 1

== Usage in Rails
The code above should work on a rails console without any issue. You will want to add a line something like:
Expand Down Expand Up @@ -112,7 +118,8 @@ This can lead to some wierd looking effects if, say, you are in the Eastern time
* David Bock http://github.com/bokmann
* Enrico Bianco http://github.com/enricob
* Arild Shirazi http://github.com/ashirazi
* Piotr Jakubowski https://github.com/piotrj
* Piotr Jakubowski http://github.com/piotrj
* Glenn Vanderburg http://github.com/glv

(Special thanks for Arild on the complexities of dealing with TimeWithZone)

Expand All @@ -128,11 +135,6 @@ This can lead to some wierd looking effects if, say, you are in the Eastern time

== TODO

* if it doesn't pollute the logic too much, I'd like to vary the days counted as 'business days'. Bakers often
don't work on Mondays, for instance. I'd do it in something like this:

BusinessTime::Config.work_week = [:tue, :wed, :thur, :fri, :sat]

* Arild has pointed out that there may be some logical inconsistencies
regaring the beginning_of_workday and end_of workday times not actually
being considered inside of the workday. I'd like to make sure that they
Expand Down
2 changes: 2 additions & 0 deletions lib/business_time.rb
@@ -1,3 +1,5 @@
require "active_support"
require "time"
require "business_time/config"
require "business_time/business_hours"
require "business_time/business_days"
Expand Down
25 changes: 25 additions & 0 deletions lib/business_time/config.rb
Expand Up @@ -17,6 +17,12 @@ class << self
# someplace in the initializers of your application.
attr_accessor :end_of_workday

# You can set this yourself, either by the load method below, or
# by saying
# BusinessTime::Config.work_week = [:sun, :mon, :tue, :wed, :thu]
# someplace in the initializers of your application.
attr_accessor :work_week

# You can set this yourself, either by the load method below, or
# by saying
# BusinessTime::Config.holidays << my_holiday_date_object
Expand All @@ -25,10 +31,28 @@ class << self

end

def self.work_week=(days)
@work_week = days
@weekdays = nil
end

def self.weekdays
return @weekdays unless @weekdays.nil?

lowercase_day_names = ::Time::RFC2822_DAY_NAME.map(&:downcase)

@weekdays = work_week.each_with_object([]) do |day_name, days|
day_num = lowercase_day_names.find_index(day_name.to_s.downcase)
days << day_num unless day_num.nil?
end
end

def self.reset
self.holidays = []
self.beginning_of_workday = "9:00 am"
self.end_of_workday = "5:00 pm"
self.work_week = %w[mon tue wed thu fri]
@weekdays = nil
end

# loads the config data from a yaml file written as:
Expand All @@ -45,6 +69,7 @@ def self.load(filename)
data = YAML::load(File.open(filename))
self.beginning_of_workday = data["business_time"]["beginning_of_workday"]
self.end_of_workday = data["business_time"]["end_of_workday"]
self.work_week = data["business_time"]["work_week"]
data["business_time"]["holidays"].each do |holiday|
self.holidays <<
Time.zone ? Time.zone.parse(holiday) : Time.parse(holiday)
Expand Down
2 changes: 1 addition & 1 deletion lib/extensions/date.rb
Expand Up @@ -5,7 +5,7 @@ def workday?
end

def weekday?
[1,2,3,4,5].include? self.wday
BusinessTime::Config.weekdays.include? self.wday
end

def business_days_until(to_date)
Expand Down
3 changes: 1 addition & 2 deletions lib/extensions/time.rb
Expand Up @@ -31,8 +31,7 @@ def workday?(day)

# True if this time falls on a weekday.
def weekday?(day)
# TODO AS: Internationalize this!
[1,2,3,4,5].include? day.wday
BusinessTime::Config.weekdays.include? day.wday
end

def before_business_hours?(time)
Expand Down
@@ -1,4 +1,4 @@
BusinessTime::Config.load("#{RAILS_ROOT}/config/business_time.yml")
BusinessTime::Config.load("#{Rails.root}/config/business_time.yml")

# or you can configure it manually: look at me! I'm Tim Ferris!
# BusinessTime.Config.beginning_of_workday = "10:00 am"
Expand Down
Expand Up @@ -4,4 +4,10 @@ business_time:
holidays:
- Jan 01, 2010
- July 4th, 2010
- December 25th, 2010
- December 25th, 2010
work_week:
- mon
- tue
- wed
- thu
- fri
3 changes: 3 additions & 0 deletions test/helper.rb
Expand Up @@ -17,4 +17,7 @@
require 'business_time'

class Test::Unit::TestCase
def teardown
BusinessTime::Config.reset
end
end
19 changes: 16 additions & 3 deletions test/test_config.rb
@@ -1,7 +1,7 @@
require 'helper'

class TestConfig < Test::Unit::TestCase

should "keep track of the start of the day" do
assert_equal "9:00 am", BusinessTime::Config.beginning_of_workday
BusinessTime::Config.beginning_of_workday = "8:30 am"
Expand All @@ -15,11 +15,24 @@ class TestConfig < Test::Unit::TestCase
end

should "keep track of holidays" do
BusinessTime::Config.reset
assert BusinessTime::Config.holidays.empty?
daves_birthday = Date.parse("August 4th, 1969")
BusinessTime::Config.holidays << daves_birthday
assert BusinessTime::Config.holidays.include?(daves_birthday)
end


should "keep track of work week" do
assert_equal %w[mon tue wed thu fri], BusinessTime::Config.work_week
BusinessTime::Config.work_week = %w[sun mon tue wed thu]
assert_equal %w[sun mon tue wed thu], BusinessTime::Config.work_week
end

should "map work week to weekdays" do
assert_equal [1,2,3,4,5], BusinessTime::Config.weekdays
BusinessTime::Config.work_week = %w[sun mon tue wed thu]
assert_equal [0,1,2,3,4], BusinessTime::Config.weekdays
BusinessTime::Config.work_week = %w[tue wed] # Hey, we got it made!
assert_equal [2,3], BusinessTime::Config.weekdays
end

end
17 changes: 9 additions & 8 deletions test/test_date_extensions.rb
@@ -1,21 +1,22 @@
require 'helper'

class TestDateExtensions < Test::Unit::TestCase

should "know what a weekend day is" do
assert(Date.parse("April 9, 2010").weekday?)
assert(!Date.parse("April 10, 2010").weekday?)
assert(!Date.parse("April 11, 2010").weekday?)
assert(Date.parse("April 12, 2010").weekday?)
end


should "know a weekend day is not a workday" do
assert(Date.parse("April 9, 2010").workday?)
assert(!Date.parse("April 10, 2010").workday?)
assert(!Date.parse("April 11, 2010").workday?)
assert(Date.parse("April 12, 2010").workday?)
end

should "know a weekend day is not a workday (with a configured work week)" do
BusinessTime::Config.work_week = %w[sun mon tue wed thu]
assert(Date.parse("April 8, 2010").weekday?)
assert(!Date.parse("April 9, 2010").weekday?)
assert(!Date.parse("April 10, 2010").weekday?)
assert(Date.parse("April 12, 2010").weekday?)
end

should "know a holiday is not a workday" do
july_4 = Date.parse("July 4, 2010")
july_5 = Date.parse("July 5, 2010")
Expand Down
15 changes: 8 additions & 7 deletions test/test_time_extensions.rb
Expand Up @@ -2,20 +2,21 @@

class TestTimeExtensions < Test::Unit::TestCase

should "know what a weekend day is" do
assert( Time.weekday?(Time.parse("April 9, 2010 10:30am")))
assert(!Time.weekday?(Time.parse("April 10, 2010 10:30am")))
assert(!Time.weekday?(Time.parse("April 11, 2010 10:30am")))
assert( Time.weekday?(Time.parse("April 12, 2010 10:30am")))
end

should "know a weekend day is not a workday" do
assert( Time.workday?(Time.parse("April 9, 2010 10:45 am")))
assert(!Time.workday?(Time.parse("April 10, 2010 10:45 am")))
assert(!Time.workday?(Time.parse("April 11, 2010 10:45 am")))
assert( Time.workday?(Time.parse("April 12, 2010 10:45 am")))
end

should "know a weekend day is not a workday (with a configured work week)" do
BusinessTime::Config.work_week = %w[sun mon tue wed thu]
assert( Time.weekday?(Time.parse("April 8, 2010 10:30am")))
assert(!Time.weekday?(Time.parse("April 9, 2010 10:30am")))
assert(!Time.weekday?(Time.parse("April 10, 2010 10:30am")))
assert( Time.weekday?(Time.parse("April 11, 2010 10:30am")))
end

should "know a holiday is not a workday" do
BusinessTime::Config.reset

Expand Down

0 comments on commit cb3189d

Please sign in to comment.