biz 1.4.0 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +70 -1
- data/lib/biz.rb +0 -1
- data/lib/biz/configuration.rb +9 -2
- data/lib/biz/interval.rb +27 -6
- data/lib/biz/schedule.rb +17 -0
- data/lib/biz/time_segment.rb +4 -14
- data/lib/biz/version.rb +1 -1
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1bfccc20f9a27336663959946a872593d35c53a3
|
4
|
+
data.tar.gz: 962e4f9927fb08f8f609e76d3f11b10949d81922
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 63aeb93f5ce1299b4164ba9ec5d537032d6f8ff174ca5b08c0fd62d62a4afec902b4528ec4d1d606899764cf20aacddd08c8cf64f95dc81348f50bf6a1446968
|
7
|
+
data.tar.gz: d81c55c540298d454bab98a9d54243cb139f2aeed16ff4b1c817479e63798dab3909dfdb43c35339646d9139a508fa78bb9f9b84a43d09863d2c38b5b36c448c
|
data/README.md
CHANGED
@@ -17,6 +17,7 @@ Time calculations using business hours.
|
|
17
17
|
- Multiple schedule configurations.
|
18
18
|
* Second-level precision on all calculations.
|
19
19
|
* Accurate handling of Daylight Saving Time.
|
20
|
+
* Schedule intersection.
|
20
21
|
* Thread-safe.
|
21
22
|
|
22
23
|
## Anti-Features
|
@@ -50,7 +51,7 @@ Biz.configure do |config|
|
|
50
51
|
sat: {'10:00' => '14:00'}
|
51
52
|
}
|
52
53
|
|
53
|
-
config.holidays = [Date.new(
|
54
|
+
config.holidays = [Date.new(2016, 1, 1), Date.new(2016, 12, 25)]
|
54
55
|
|
55
56
|
config.time_zone = 'America/Los_Angeles'
|
56
57
|
end
|
@@ -120,6 +121,74 @@ Biz.periods
|
|
120
121
|
# #<Biz::TimeSegment start_time=2015-04-27 20:36:57 UTC end_time=2015-04-28 00:00:00 UTC>]
|
121
122
|
```
|
122
123
|
|
124
|
+
## Schedule Intersection
|
125
|
+
|
126
|
+
An intersection of two schedules can be found using `&`:
|
127
|
+
|
128
|
+
```ruby
|
129
|
+
schedule_1 = Biz::Schedule.new do |config|
|
130
|
+
config.hours = {
|
131
|
+
mon: {'09:00' => '17:00'},
|
132
|
+
tue: {'10:00' => '16:00'},
|
133
|
+
wed: {'09:00' => '17:00'},
|
134
|
+
thu: {'10:00' => '16:00'},
|
135
|
+
fri: {'09:00' => '17:00'},
|
136
|
+
sat: {'11:00' => '14:30'}
|
137
|
+
}
|
138
|
+
|
139
|
+
config.holidays = [Date.new(2016, 1, 1), Date.new(2016, 12, 25)]
|
140
|
+
|
141
|
+
config.time_zone = 'Etc/UTC'
|
142
|
+
end
|
143
|
+
|
144
|
+
schedule_2 = Biz::Schedule.new do |config|
|
145
|
+
config.hours = {
|
146
|
+
sun: {'10:00' => '12:00'},
|
147
|
+
mon: {'08:00' => '10:00'},
|
148
|
+
tue: {'11:00' => '15:00'},
|
149
|
+
wed: {'16:00' => '18:00'},
|
150
|
+
thu: {'11:00' => '12:00', '13:00' => '14:00'}
|
151
|
+
}
|
152
|
+
|
153
|
+
config.holidays = [
|
154
|
+
Date.new(2016, 1, 1),
|
155
|
+
Date.new(2016, 7, 4),
|
156
|
+
Date.new(2016, 11, 24)
|
157
|
+
]
|
158
|
+
|
159
|
+
config.time_zone = 'America/Los_Angeles'
|
160
|
+
end
|
161
|
+
|
162
|
+
schedule_1 & schedule_2
|
163
|
+
```
|
164
|
+
|
165
|
+
The resulting schedule will be a combination of the two schedules: an
|
166
|
+
intersection of the intervals, a union of the holidays, and the time zone of the
|
167
|
+
first schedule.
|
168
|
+
|
169
|
+
For the above example, the resulting schedule would be equivalent to one with
|
170
|
+
the following configuration:
|
171
|
+
|
172
|
+
```ruby
|
173
|
+
Biz::Schedule.new do |config|
|
174
|
+
config.hours = {
|
175
|
+
mon: {'09:00' => '10:00'},
|
176
|
+
tue: {'11:00' => '15:00'},
|
177
|
+
wed: {'16:00' => '17:00'},
|
178
|
+
thu: {'11:00' => '12:00', '13:00' => '14:00'}
|
179
|
+
}
|
180
|
+
|
181
|
+
config.holidays = [
|
182
|
+
Date.new(2016, 1, 1),
|
183
|
+
Date.new(2016, 7, 4),
|
184
|
+
Date.new(2016, 11, 24),
|
185
|
+
Date.new(2016, 12, 25)
|
186
|
+
]
|
187
|
+
|
188
|
+
config.time_zone = 'Etc/UTC'
|
189
|
+
end
|
190
|
+
```
|
191
|
+
|
123
192
|
## Core Extensions
|
124
193
|
|
125
194
|
Optional extensions to core classes (`Date`, `Fixnum`, and `Time`) are available
|
data/lib/biz.rb
CHANGED
data/lib/biz/configuration.rb
CHANGED
@@ -7,6 +7,8 @@ module Biz
|
|
7
7
|
yield raw if block_given?
|
8
8
|
|
9
9
|
Validation.perform(raw)
|
10
|
+
|
11
|
+
raw.freeze
|
10
12
|
end
|
11
13
|
|
12
14
|
def intervals
|
@@ -21,7 +23,12 @@ module Biz
|
|
21
23
|
|
22
24
|
def holidays
|
23
25
|
@holidays ||= begin
|
24
|
-
raw
|
26
|
+
raw
|
27
|
+
.holidays
|
28
|
+
.uniq
|
29
|
+
.map { |date| Holiday.new(date, time_zone) }
|
30
|
+
.sort
|
31
|
+
.freeze
|
25
32
|
end
|
26
33
|
end
|
27
34
|
|
@@ -30,7 +37,7 @@ module Biz
|
|
30
37
|
end
|
31
38
|
|
32
39
|
def weekdays
|
33
|
-
@weekdays ||= raw.hours.keys.
|
40
|
+
@weekdays ||= raw.hours.keys.uniq.freeze
|
34
41
|
end
|
35
42
|
|
36
43
|
protected
|
data/lib/biz/interval.rb
CHANGED
@@ -1,18 +1,38 @@
|
|
1
1
|
module Biz
|
2
2
|
class Interval
|
3
3
|
|
4
|
+
extend Forwardable
|
5
|
+
|
4
6
|
include Comparable
|
5
7
|
|
8
|
+
def self.to_hours(intervals)
|
9
|
+
intervals.each_with_object(
|
10
|
+
Hash.new do |hours, wday| hours.store(wday, {}) end
|
11
|
+
) do |interval, hours|
|
12
|
+
hours[interval.wday_symbol].store(*interval.endpoints.map(&:timestamp))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
6
16
|
def initialize(start_time, end_time, time_zone)
|
7
17
|
@start_time = start_time
|
8
18
|
@end_time = end_time
|
9
19
|
@time_zone = time_zone
|
10
20
|
end
|
11
21
|
|
22
|
+
attr_reader :start_time,
|
23
|
+
:end_time,
|
24
|
+
:time_zone
|
25
|
+
|
26
|
+
delegate wday_symbol: :start_time
|
27
|
+
|
12
28
|
def endpoints
|
13
29
|
[start_time, end_time]
|
14
30
|
end
|
15
31
|
|
32
|
+
def empty?
|
33
|
+
start_time >= end_time
|
34
|
+
end
|
35
|
+
|
16
36
|
def contains?(time)
|
17
37
|
(start_time...end_time).cover?(
|
18
38
|
WeekTime.from_time(Time.new(time_zone).local(time))
|
@@ -27,6 +47,13 @@ module Biz
|
|
27
47
|
)
|
28
48
|
end
|
29
49
|
|
50
|
+
def &(other)
|
51
|
+
lower_bound = [self, other].map(&:start_time).max
|
52
|
+
upper_bound = [self, other].map(&:end_time).min
|
53
|
+
|
54
|
+
self.class.new(lower_bound, [lower_bound, upper_bound].max, time_zone)
|
55
|
+
end
|
56
|
+
|
30
57
|
def <=>(other)
|
31
58
|
return unless other.is_a?(self.class)
|
32
59
|
|
@@ -34,11 +61,5 @@ module Biz
|
|
34
61
|
[other.start_time, other.end_time, other.time_zone]
|
35
62
|
end
|
36
63
|
|
37
|
-
protected
|
38
|
-
|
39
|
-
attr_reader :start_time,
|
40
|
-
:end_time,
|
41
|
-
:time_zone
|
42
|
-
|
43
64
|
end
|
44
65
|
end
|
data/lib/biz/schedule.rb
CHANGED
@@ -46,6 +46,23 @@ module Biz
|
|
46
46
|
Time.new(time_zone)
|
47
47
|
end
|
48
48
|
|
49
|
+
def &(other)
|
50
|
+
self.class.new do |config|
|
51
|
+
config.hours = Interval.to_hours(
|
52
|
+
intervals.flat_map { |interval|
|
53
|
+
other
|
54
|
+
.intervals
|
55
|
+
.map { |other_interval| interval & other_interval }
|
56
|
+
.reject(&:empty?)
|
57
|
+
}
|
58
|
+
)
|
59
|
+
|
60
|
+
config.holidays = [*holidays, *other.holidays].map(&:to_date)
|
61
|
+
|
62
|
+
config.time_zone = time_zone.name
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
49
66
|
protected
|
50
67
|
|
51
68
|
attr_reader :configuration
|
data/lib/biz/time_segment.rb
CHANGED
@@ -36,10 +36,10 @@ module Biz
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def &(other)
|
39
|
-
self.
|
40
|
-
|
41
|
-
|
42
|
-
)
|
39
|
+
lower_bound = [self, other].map(&:start_time).max
|
40
|
+
upper_bound = [self, other].map(&:end_time).min
|
41
|
+
|
42
|
+
self.class.new(lower_bound, [lower_bound, upper_bound].max)
|
43
43
|
end
|
44
44
|
|
45
45
|
def <=>(other)
|
@@ -48,15 +48,5 @@ module Biz
|
|
48
48
|
[start_time, end_time] <=> [other.start_time, other.end_time]
|
49
49
|
end
|
50
50
|
|
51
|
-
private
|
52
|
-
|
53
|
-
def lower_bound(other)
|
54
|
-
[self, other].map(&:start_time).max
|
55
|
-
end
|
56
|
-
|
57
|
-
def upper_bound(other)
|
58
|
-
[self, other].map(&:end_time).min
|
59
|
-
end
|
60
|
-
|
61
51
|
end
|
62
52
|
end
|
data/lib/biz/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: biz
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Craig Little
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2016-03-
|
12
|
+
date: 2016-03-30 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: clavius
|
@@ -45,14 +45,14 @@ dependencies:
|
|
45
45
|
requirements:
|
46
46
|
- - "~>"
|
47
47
|
- !ruby/object:Gem::Version
|
48
|
-
version: '
|
48
|
+
version: '11.0'
|
49
49
|
type: :development
|
50
50
|
prerelease: false
|
51
51
|
version_requirements: !ruby/object:Gem::Requirement
|
52
52
|
requirements:
|
53
53
|
- - "~>"
|
54
54
|
- !ruby/object:Gem::Version
|
55
|
-
version: '
|
55
|
+
version: '11.0'
|
56
56
|
- !ruby/object:Gem::Dependency
|
57
57
|
name: rspec
|
58
58
|
requirement: !ruby/object:Gem::Requirement
|
@@ -135,7 +135,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
135
135
|
version: '0'
|
136
136
|
requirements: []
|
137
137
|
rubyforge_project:
|
138
|
-
rubygems_version: 2.
|
138
|
+
rubygems_version: 2.2.2
|
139
139
|
signing_key:
|
140
140
|
specification_version: 4
|
141
141
|
summary: Business hours calculations
|