alphasights-business_time 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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