alphasights-business_time 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,18 @@
1
+ # hook into fixnum so we can say things like:
2
+ # 5.business_hours.from_now
3
+ # 7.business_days.ago
4
+ # 3.business_days.after(some_date)
5
+ # 4.business_hours.before(some_date_time)
6
+ class Fixnum
7
+ include BusinessTime
8
+
9
+ def business_hours
10
+ BusinessHours.new(self)
11
+ end
12
+ alias_method :business_hour, :business_hours
13
+
14
+ def business_days
15
+ BusinessDays.new(self)
16
+ end
17
+ alias_method :business_day, :business_days
18
+ end
@@ -0,0 +1,109 @@
1
+ # Add workday and weekday concepts to the Time class
2
+ class Time
3
+ class << self
4
+
5
+ # Gives the time at the end of the workday, assuming that this time falls on a
6
+ # workday.
7
+ # Note: It pretends that this day is a workday whether or not it really is a
8
+ # workday.
9
+ def end_of_workday(day)
10
+ format = "%B %d %Y #{BusinessTime::Config.end_of_workday}"
11
+ Time.zone ? Time.zone.parse(day.strftime(format)) :
12
+ Time.parse(day.strftime(format))
13
+ end
14
+
15
+ # Gives the time at the beginning of the workday, assuming that this time
16
+ # falls on a workday.
17
+ # Note: It pretends that this day is a workday whether or not it really is a
18
+ # workday.
19
+ def beginning_of_workday(day)
20
+ format = "%B %d %Y #{BusinessTime::Config.beginning_of_workday}"
21
+ Time.zone ? Time.zone.parse(day.strftime(format)) :
22
+ Time.parse(day.strftime(format))
23
+ end
24
+
25
+ # True if this time is on a workday (between 00:00:00 and 23:59:59), even if
26
+ # this time falls outside of normal business hours.
27
+ def workday?(day)
28
+ Time.weekday?(day) &&
29
+ !BusinessTime::Config.holidays.include?(day.to_date)
30
+ end
31
+
32
+ # True if this time falls on a weekday.
33
+ def weekday?(day)
34
+ # TODO AS: Internationalize this!
35
+ [1,2,3,4,5].include? day.wday
36
+ end
37
+
38
+ def before_business_hours?(time)
39
+ time < beginning_of_workday(time)
40
+ end
41
+
42
+ def after_business_hours?(time)
43
+ time > end_of_workday(time)
44
+ end
45
+
46
+ def during_business_hours?(time)
47
+ workday?(time) && !before_business_hours?(time) && !after_business_hours?(time)
48
+ end
49
+
50
+ # Rolls forward to the next beginning_of_workday
51
+ # when the time is outside of business hours
52
+ def roll_forward(time)
53
+
54
+ if (Time.before_business_hours?(time) || !Time.workday?(time))
55
+ next_business_time = Time.beginning_of_workday(time)
56
+ elsif Time.after_business_hours?(time)
57
+ next_business_time = Time.beginning_of_workday(time) + 1.day
58
+ else
59
+ next_business_time = time.clone
60
+ end
61
+
62
+ while !Time.workday?(next_business_time)
63
+ next_business_time += 1.day
64
+ end
65
+
66
+ next_business_time
67
+ end
68
+
69
+ end
70
+
71
+ def business_time_left_to(time)
72
+ if time.to_date == self.to_date
73
+ end
74
+ time_left = 0
75
+ start_day = self
76
+ while start_day.to_date < time.to_date
77
+ parsed_start_day = Time.parse(start_day.to_s)
78
+ time_left += start_day.business_time_left_to_end
79
+ start_day = Time.beginning_of_workday(parsed_start_day) + 1.day
80
+ end
81
+ time_left += time.business_time_passed_from_beginning
82
+ time_left
83
+ end
84
+
85
+ def business_time_left_to_end
86
+ time = Time.parse(self.to_s)
87
+ workday = Time.workday?(time)
88
+ if workday && Time.during_business_hours?(time)
89
+ Time.end_of_workday(time) - self
90
+ elsif Time.before_business_hours?(time) && workday
91
+ Time.end_of_workday(time) - Time.beginning_of_workday(time)
92
+ else
93
+ 0
94
+ end
95
+ end
96
+
97
+ def business_time_passed_from_beginning
98
+ time = Time.parse(self.to_s)
99
+ workday = Time.workday?(time)
100
+ if workday && Time.during_business_hours?(time)
101
+ self - Time.beginning_of_workday(time)
102
+ elsif Time.after_business_hours?(time) && workday
103
+ Time.end_of_workday(time) - Time.beginning_of_workday(time)
104
+ else
105
+ 0
106
+ end
107
+ end
108
+
109
+ end
@@ -0,0 +1,21 @@
1
+ module BusinessTime
2
+ module Generators
3
+ class ConfigGenerator < Rails::Generators::Base # :nodoc:
4
+
5
+ def self.gem_root
6
+ File.expand_path("../../../..", __FILE__)
7
+ end
8
+
9
+ def self.source_root
10
+ # Use the templates from the 2.3.x generator
11
+ File.join(gem_root, 'rails_generators', 'business_time_config', 'templates')
12
+ end
13
+
14
+ def generate
15
+ template 'business_time.rb', File.join('config', 'initializers', 'business_time.rb')
16
+ template 'business_time.yml', File.join('config', 'business_time.yml')
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,11 @@
1
+ # This generator simply drops the business_time.rb and business_time.yml file
2
+ # into the appropate places in a rails app to configure and initialize the
3
+ # data. Once generated, these files are yours to modify.
4
+ class BusinessTimeConfigGenerator < Rails::Generator::Base
5
+ def manifest
6
+ record do |m|
7
+ m.template('business_time.rb', "config/initializers/business_time.rb")
8
+ m.template('business_time.yml', "config/business_time.yml")
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,6 @@
1
+ BusinessTime::Config.load("#{RAILS_ROOT}/config/business_time.yml")
2
+
3
+ # or you can configure it manually: look at me! I'm Tim Ferris!
4
+ # BusinessTime.Config.beginning_of_workday = "10:00 am"
5
+ # BusinessTime.Comfig.end_of_workday = "11:30 am"
6
+ # BusinessTime.config.holidays << Date.parse("August 4th, 2010")
@@ -0,0 +1,7 @@
1
+ business_time:
2
+ beginning_of_workday: 9:00 am
3
+ end_of_workday: 5:00 pm
4
+ holidays:
5
+ - Jan 01, 2010
6
+ - July 4th, 2010
7
+ - December 25th, 2010
@@ -0,0 +1,20 @@
1
+ require 'rubygems'
2
+
3
+ if RUBY_VERSION >= '1.9'
4
+ require 'time'
5
+ require 'date'
6
+ require 'active_support/time'
7
+ else
8
+ require 'active_support'
9
+ require 'active_support/core_ext'
10
+ end
11
+
12
+ require 'test/unit'
13
+ require 'shoulda'
14
+
15
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
16
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
17
+ require 'business_time'
18
+
19
+ class Test::Unit::TestCase
20
+ end
@@ -0,0 +1,69 @@
1
+ require 'helper'
2
+
3
+ class TestBusinessDays < Test::Unit::TestCase
4
+
5
+ context "with a standard Time object" do
6
+
7
+ should "move to tomorrow if we add a business day" do
8
+ first = Time.parse("April 13th, 2010, 11:00 am")
9
+ later = 1.business_day.after(first)
10
+ expected = Time.parse("April 14th, 2010, 11:00 am")
11
+ assert_equal expected, later
12
+ end
13
+
14
+ should "move to yesterday is we subtract a business day" do
15
+ first = Time.parse("April 13th, 2010, 11:00 am")
16
+ before = 1.business_day.before(first)
17
+ expected = Time.parse("April 12th, 2010, 11:00 am")
18
+ assert_equal expected, before
19
+ end
20
+
21
+ should "take into account the weekend when adding a day" do
22
+ first = Time.parse("April 9th, 2010, 12:33 pm")
23
+ after = 1.business_day.after(first)
24
+ expected = Time.parse("April 12th, 2010, 12:33 pm")
25
+ assert_equal expected, after
26
+ end
27
+
28
+ should "take into account the weekend when subtracting a day" do
29
+ first = Time.parse("April 12th, 2010, 12:33 pm")
30
+ before = 1.business_day.before(first)
31
+ expected = Time.parse("April 9th, 2010, 12:33 pm")
32
+ assert_equal expected, before
33
+ end
34
+
35
+ should "move forward one week when adding 5 business days" do
36
+ first = Time.parse("April 9th, 2010, 12:33 pm")
37
+ after = 5.business_days.after(first)
38
+ expected = Time.parse("April 16th, 2010, 12:33 pm")
39
+ assert_equal expected, after
40
+ end
41
+
42
+ should "move backward one week when subtracting 5 business days" do
43
+ first = Time.parse("April 16th, 2010, 12:33 pm")
44
+ before = 5.business_days.before(first)
45
+ expected = Time.parse("April 9th, 2010, 12:33 pm")
46
+ assert_equal expected, before
47
+ end
48
+
49
+ should "take into account a holiday when adding a day" do
50
+ three_day_weekend = Date.parse("July 5th, 2010")
51
+ BusinessTime::Config.holidays << three_day_weekend
52
+ friday_afternoon = Time.parse("July 2nd, 2010, 4:50 pm")
53
+ tuesday_afternoon = 1.business_day.after(friday_afternoon)
54
+ expected = Time.parse("July 6th, 2010, 4:50 pm")
55
+ assert_equal expected, tuesday_afternoon
56
+ end
57
+
58
+ should "take into account a holiday on a weekend" do
59
+ BusinessTime::Config.reset
60
+ july_4 = Date.parse("July 4th, 2010")
61
+ BusinessTime::Config.holidays << july_4
62
+ friday_afternoon = Time.parse("July 2nd, 2010, 4:50 pm")
63
+ monday_afternoon = 1.business_day.after(friday_afternoon)
64
+ expected = Time.parse("July 5th, 2010, 4:50 pm")
65
+ assert_equal expected, monday_afternoon
66
+ end
67
+ end
68
+
69
+ end
@@ -0,0 +1,75 @@
1
+ require 'helper'
2
+
3
+ class TestBusinessDays < Test::Unit::TestCase
4
+
5
+ context "with a TimeWithZone object set to the Eastern timezone" do
6
+ setup do
7
+ Time.zone = 'Eastern Time (US & Canada)'
8
+ end
9
+ teardown do
10
+ Time.zone = nil
11
+ end
12
+
13
+ should "move to tomorrow if we add a business day" do
14
+ first = Time.zone.parse("April 13th, 2010, 11:00 am")
15
+ later = 1.business_day.after(first)
16
+ expected = Time.zone.parse("April 14th, 2010, 11:00 am")
17
+ assert_equal expected, later
18
+ end
19
+
20
+ should "move to yesterday is we subtract a business day" do
21
+ first = Time.zone.parse("April 13th, 2010, 11:00 am")
22
+ before = 1.business_day.before(first)
23
+ expected = Time.zone.parse("April 12th, 2010, 11:00 am")
24
+ assert_equal expected, before
25
+ end
26
+
27
+ should "take into account the weekend when adding a day" do
28
+ first = Time.zone.parse("April 9th, 2010, 12:33 pm")
29
+ after = 1.business_day.after(first)
30
+ expected = Time.zone.parse("April 12th, 2010, 12:33 pm")
31
+ assert_equal expected, after
32
+ end
33
+
34
+ should "take into account the weekend when subtracting a day" do
35
+ first = Time.zone.parse("April 12th, 2010, 12:33 pm")
36
+ before = 1.business_day.before(first)
37
+ expected = Time.zone.parse("April 9th, 2010, 12:33 pm")
38
+ assert_equal expected, before
39
+ end
40
+
41
+ should "move forward one week when adding 5 business days" do
42
+ first = Time.zone.parse("April 9th, 2010, 12:33 pm")
43
+ after = 5.business_days.after(first)
44
+ expected = Time.zone.parse("April 16th, 2010, 12:33 pm")
45
+ assert_equal expected, after
46
+ end
47
+
48
+ should "move backward one week when subtracting 5 business days" do
49
+ first = Time.zone.parse("April 16th, 2010, 12:33 pm")
50
+ before = 5.business_days.before(first)
51
+ expected = Time.zone.parse("April 9th, 2010, 12:33 pm")
52
+ assert_equal expected, before
53
+ end
54
+
55
+ should "take into account a holiday when adding a day" do
56
+ three_day_weekend = Date.parse("July 5th, 2010")
57
+ BusinessTime::Config.holidays << three_day_weekend
58
+ friday_afternoon = Time.zone.parse("July 2nd, 2010, 4:50 pm")
59
+ tuesday_afternoon = 1.business_day.after(friday_afternoon)
60
+ expected = Time.zone.parse("July 6th, 2010, 4:50 pm")
61
+ assert_equal expected, tuesday_afternoon
62
+ end
63
+
64
+ should "take into account a holiday on a weekend" do
65
+ BusinessTime::Config.reset
66
+ july_4 = Date.parse("July 4th, 2010")
67
+ BusinessTime::Config.holidays << july_4
68
+ friday_afternoon = Time.zone.parse("July 2nd, 2010, 4:50 pm")
69
+ monday_afternoon = 1.business_day.after(friday_afternoon)
70
+ expected = Time.zone.parse("July 5th, 2010, 4:50 pm")
71
+ assert_equal expected, monday_afternoon
72
+ end
73
+ end
74
+
75
+ end
@@ -0,0 +1,75 @@
1
+ require 'helper'
2
+
3
+ class TestBusinessDays < Test::Unit::TestCase
4
+
5
+ context "with a TimeWithZone object set to UTC" do
6
+ setup do
7
+ Time.zone = 'UTC'
8
+ end
9
+ teardown do
10
+ Time.zone = nil
11
+ end
12
+
13
+ should "move to tomorrow if we add a business day" do
14
+ first = Time.zone.parse("April 13th, 2010, 11:00 am")
15
+ later = 1.business_day.after(first)
16
+ expected = Time.zone.parse("April 14th, 2010, 11:00 am")
17
+ assert_equal expected, later
18
+ end
19
+
20
+ should "move to yesterday is we subtract a business day" do
21
+ first = Time.zone.parse("April 13th, 2010, 11:00 am")
22
+ before = 1.business_day.before(first)
23
+ expected = Time.zone.parse("April 12th, 2010, 11:00 am")
24
+ assert_equal expected, before
25
+ end
26
+
27
+ should "take into account the weekend when adding a day" do
28
+ first = Time.zone.parse("April 9th, 2010, 12:33 pm")
29
+ after = 1.business_day.after(first)
30
+ expected = Time.zone.parse("April 12th, 2010, 12:33 pm")
31
+ assert_equal expected, after
32
+ end
33
+
34
+ should "take into account the weekend when subtracting a day" do
35
+ first = Time.zone.parse("April 12th, 2010, 12:33 pm")
36
+ before = 1.business_day.before(first)
37
+ expected = Time.zone.parse("April 9th, 2010, 12:33 pm")
38
+ assert_equal expected, before
39
+ end
40
+
41
+ should "move forward one week when adding 5 business days" do
42
+ first = Time.zone.parse("April 9th, 2010, 12:33 pm")
43
+ after = 5.business_days.after(first)
44
+ expected = Time.zone.parse("April 16th, 2010, 12:33 pm")
45
+ assert_equal expected, after
46
+ end
47
+
48
+ should "move backward one week when subtracting 5 business days" do
49
+ first = Time.zone.parse("April 16th, 2010, 12:33 pm")
50
+ before = 5.business_days.before(first)
51
+ expected = Time.zone.parse("April 9th, 2010, 12:33 pm")
52
+ assert_equal expected, before
53
+ end
54
+
55
+ should "take into account a holiday when adding a day" do
56
+ three_day_weekend = Date.parse("July 5th, 2010")
57
+ BusinessTime::Config.holidays << three_day_weekend
58
+ friday_afternoon = Time.zone.parse("July 2nd, 2010, 4:50 pm")
59
+ tuesday_afternoon = 1.business_day.after(friday_afternoon)
60
+ expected = Time.zone.parse("July 6th, 2010, 4:50 pm")
61
+ assert_equal expected, tuesday_afternoon
62
+ end
63
+
64
+ should "take into account a holiday on a weekend" do
65
+ BusinessTime::Config.reset
66
+ july_4 = Date.parse("July 4th, 2010")
67
+ BusinessTime::Config.holidays << july_4
68
+ friday_afternoon = Time.zone.parse("July 2nd, 2010, 4:50 pm")
69
+ monday_afternoon = 1.business_day.after(friday_afternoon)
70
+ expected = Time.zone.parse("July 5th, 2010, 4:50 pm")
71
+ assert_equal expected, monday_afternoon
72
+ end
73
+ end
74
+
75
+ end
@@ -0,0 +1,69 @@
1
+ require 'helper'
2
+
3
+ class TestBusinessHours < Test::Unit::TestCase
4
+
5
+ context "with a standard Time object" do
6
+
7
+ should "move to tomorrow if we add 8 business hours" do
8
+ first = Time.parse("Aug 4 2010, 9:35 am")
9
+ later = 8.business_hours.after(first)
10
+ expected = Time.parse("Aug 5 2010, 9:35 am")
11
+ assert_equal expected, later
12
+ end
13
+
14
+ should "move to yesterday if we subtract 8 business hours" do
15
+ first = Time.parse("Aug 4 2010, 9:35 am")
16
+ later = 8.business_hours.before(first)
17
+ expected = Time.parse("Aug 3 2010, 9:35 am")
18
+ assert_equal expected, later
19
+ end
20
+
21
+ should "take into account a weekend when adding an hour" do
22
+ friday_afternoon = Time.parse("April 9th, 4:50 pm")
23
+ monday_morning = 1.business_hour.after(friday_afternoon)
24
+ expected = Time.parse("April 12th 2010, 9:50 am")
25
+ assert_equal expected, monday_morning
26
+ end
27
+
28
+ should "take into account a weekend when subtracting an hour" do
29
+ monday_morning = Time.parse("April 12th 2010, 9:50 am")
30
+ friday_afternoon = 1.business_hour.before(monday_morning)
31
+ expected = Time.parse("April 9th 2010, 4:50 pm")
32
+ assert_equal expected, friday_afternoon
33
+ end
34
+
35
+ should "take into account a holiday" do
36
+ BusinessTime::Config.holidays << Date.parse("July 5th, 2010")
37
+ friday_afternoon = Time.parse("July 2nd 2010, 4:50pm")
38
+ tuesday_morning = 1.business_hour.after(friday_afternoon)
39
+ expected = Time.parse("July 6th 2010, 9:50 am")
40
+ assert_equal expected, tuesday_morning
41
+ end
42
+
43
+ should "add hours in the middle of the workday" do
44
+ monday_morning = Time.parse("April 12th 2010, 9:50 am")
45
+ later = 3.business_hours.after(monday_morning)
46
+ expected = Time.parse("April 12th 2010, 12:50 pm")
47
+ assert_equal expected, later
48
+ end
49
+
50
+ should "roll forward to 9 am if asked in the early morning" do
51
+ crack_of_dawn_monday = Time.parse("Mon Apr 26, 04:30:00, 2010")
52
+ monday_morning = Time.parse("Mon Apr 26, 09:00:00, 2010")
53
+ assert_equal monday_morning, Time.roll_forward(crack_of_dawn_monday)
54
+ end
55
+
56
+ should "roll forward to the next morning if aftern business hours" do
57
+ monday_evening = Time.parse("Mon Apr 26, 18:00:00, 2010")
58
+ tuesday_morning = Time.parse("Tue Apr 27, 09:00:00, 2010")
59
+ assert_equal tuesday_morning, Time.roll_forward(monday_evening)
60
+ end
61
+
62
+ should "consider any time on a weekend as equivalent to monday morning" do
63
+ sunday = Time.parse("Sun Apr 25 12:06:56, 2010")
64
+ monday = Time.parse("Mon Apr 26, 09:00:00, 2010")
65
+ assert_equal 1.business_hour.before(monday), 1.business_hour.before(sunday)
66
+ end
67
+ end
68
+
69
+ end