working_hours 1.1.1 → 1.1.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fdc5713f20da1316a29bf18573095ac9e92ccb6c
4
- data.tar.gz: bf54ee89ba3f855fcdc0d791965cf23fd5c29d3c
3
+ metadata.gz: 67a0f2eb365a59918de39db2f11c29793a458f07
4
+ data.tar.gz: 003cae888ac4274d8fa53fffee04c8bddb83b3b8
5
5
  SHA512:
6
- metadata.gz: 99cd033ae02a2c9c25fbced88e1c265a891210c7a232e12bb32191fd3c9bcea652cf3f35bd6c50c3215277b190d3af56e73fbde20cff1bb6cdfb24e2a205e08f
7
- data.tar.gz: 50f2ca92979404a58af287abd33dd7af125ad9366a43160804bbbf09ce2b7648d474c5bf598e583fef4c7394e28965c31a91cc26a3ebba35d71e12cba0cdff95
6
+ metadata.gz: 1917dd8e540d5b79d19f85c4c29ee10951f42f37a86451eacbaa9e03522db3f76b93051358d87404bb74df3ead6c2940c029f7b80e713af861a3517e562f692a
7
+ data.tar.gz: 78aaf458c8bf63b49f9a94cf9134a9f6f95ae8293075d799acca986ef5b6da4417fae2315f1450d404884384864f67fc8ae51482d5f75fc02727df76a43d5dbf
data/.gitignore CHANGED
@@ -3,6 +3,8 @@
3
3
  .bundle
4
4
  .config
5
5
  .yardoc
6
+ .ruby-gemset
7
+ .ruby-version
6
8
  Gemfile.lock
7
9
  InstalledFiles
8
10
  _yardoc
data/.travis.yml CHANGED
@@ -2,7 +2,7 @@ language: ruby
2
2
  rvm:
3
3
  - 2.0.0
4
4
  - 2.1.6
5
- - 2.2.2
5
+ - 2.2.3
6
6
  - ruby-head
7
7
  - jruby-1.7.19
8
8
  - jruby-head
data/CHANGELOG.md CHANGED
@@ -1,6 +1,12 @@
1
1
  # Unreleased
2
2
 
3
- [Compare master with v1.1.1](https://github.com/intrepidd/working_hours/compare/v1.1.1...master)
3
+ [Compare master with v1.1.2](https://github.com/intrepidd/working_hours/compare/v1.1.2...master)
4
+
5
+ # v1.1.2
6
+ * Fixed an issue of float imprecision causing infinite loop - [#27](https://github.com/Intrepidd/working_hours/pull/27)
7
+ * Added #next_working_time and #advance_to_closing_time - [#23](https://github.com/Intrepidd/working_hours/pull/23)
8
+
9
+ _06/12/2015_
4
10
 
5
11
  # v1.1.1
6
12
  * Fix infinite loop happening when rewinding seconds and crossing through midgnight
data/README.md CHANGED
@@ -57,6 +57,16 @@ Time.utc(2014, 8, 4, 7, 16).in_working_hours? # => false
57
57
  # Advance to next working time
58
58
  WorkingHours.advance_to_working_time(Time.utc(2014, 8, 4, 7, 16)) # => Mon, 04 Aug 2014 09:00:00 UTC +00:00
59
59
 
60
+ # Advance to next closing time
61
+ WorkingHours.advance_to_closing_time(Time.utc(2014, 8, 4, 7, 16)) # => Mon, 04 Aug 2014 17:00:00 UTC +00:00
62
+ WorkingHours.advance_to_closing_time(Time.utc(2014, 8, 4, 10, 16)) # => Mon, 04 Aug 2014 17:00:00 UTC +00:00
63
+ WorkingHours.advance_to_closing_time(Time.utc(2014, 8, 4, 18, 16)) # => Tue, 05 Aug 2014 17:00:00 UTC +00:00
64
+
65
+ # Next working time
66
+ sunday = Time.utc(2014, 8, 3)
67
+ monday = WorkingHours.next_working_time(sunday) # => Mon, 04 Aug 2014 09:00:00 UTC +00:00
68
+ tuesday = WorkingHours.next_working_time(monday) # => Tue, 05 Aug 2014 09:00:00 UTC +00:00
69
+
60
70
  # Return to previous working time
61
71
  WorkingHours.return_to_working_time(Time.utc(2014, 8, 4, 7, 16)) # => Fri, 01 Aug 2014 17:00:00 UTC +00:00
62
72
  ```
@@ -39,7 +39,7 @@ module WorkingHours
39
39
  config[:working_hours][time.wday].each do |from, to|
40
40
  if time_in_day >= from and time_in_day < to
41
41
  # take all we can
42
- take = [to - time_in_day, seconds].min.round
42
+ take = [to - time_in_day, seconds].min
43
43
  # advance time
44
44
  time += take
45
45
  # decrease seconds
@@ -55,7 +55,7 @@ module WorkingHours
55
55
  config[:working_hours][time.wday].reverse_each do |from, to|
56
56
  if time_in_day > from and time_in_day <= to
57
57
  # take all we can
58
- take = [time_in_day - from, -seconds].min.round
58
+ take = [time_in_day - from, -seconds].min
59
59
  # advance time
60
60
  time -= take
61
61
  # decrease seconds
@@ -85,6 +85,31 @@ module WorkingHours
85
85
  end
86
86
  end
87
87
 
88
+ def advance_to_closing_time time, config: nil
89
+ config ||= wh_config
90
+ time = in_config_zone(time, config: config).round
91
+ loop do
92
+ # skip holidays and weekends
93
+ while not working_day?(time, config: config)
94
+ time = (time + 1.day).beginning_of_day
95
+ end
96
+ # find next working range after time
97
+ time_in_day = time.seconds_since_midnight
98
+ time = time.beginning_of_day
99
+ (config[:working_hours][time.wday] || {}).each do |from, to|
100
+ return time + to if time_in_day >= from and time_in_day < to
101
+ return time + to if from >= time_in_day
102
+ end
103
+ # if none is found, go to next day and loop
104
+ time = time + 1.day
105
+ end
106
+ end
107
+
108
+ def next_working_time(time, config: nil)
109
+ time = advance_to_closing_time(time, config: config) if in_working_hours?(time, config: config)
110
+ advance_to_working_time(time, config: config)
111
+ end
112
+
88
113
  def return_to_working_time(time, config: nil)
89
114
  # return_to_exact_working_time may return values with a high number of milliseconds,
90
115
  # this is necessary for the end of day hack, here we return a rounded value for the
@@ -1,3 +1,3 @@
1
1
  module WorkingHours
2
- VERSION = "1.1.1"
2
+ VERSION = "1.1.2"
3
3
  end
@@ -148,6 +148,173 @@ describe WorkingHours::Computation do
148
148
  end
149
149
  end
150
150
 
151
+ describe '#advance_to_closing_time' do
152
+
153
+ it 'jumps non-working day' do
154
+ WorkingHours::Config.holidays = [Date.new(2014, 5, 1)]
155
+ holiday = Time.utc(2014, 5, 1, 12, 0)
156
+ friday_closing = Time.utc(2014, 5, 2, 17, 0)
157
+ sunday = Time.utc(2014, 6, 1, 12, 0)
158
+ monday_closing = Time.utc(2014, 6, 2, 17, 0)
159
+ expect(advance_to_closing_time(holiday)).to eq(friday_closing)
160
+ expect(advance_to_closing_time(sunday)).to eq(monday_closing)
161
+ end
162
+
163
+ it 'moves to the closing time during working hours' do
164
+ in_open_time = Time.utc(2014, 4, 7, 12, 0)
165
+ closing_time = Time.utc(2014, 4, 7, 17, 0)
166
+ expect(advance_to_closing_time(in_open_time)).to eq(closing_time)
167
+ end
168
+
169
+ it 'jumps outside working hours' do
170
+ monday_before_opening = Time.utc(2014, 4, 7, 8, 59)
171
+ monday_closing = Time.utc(2014, 4, 7, 17, 0)
172
+ tuesday_closing = Time.utc(2014, 4, 8, 17, 0)
173
+ expect(advance_to_closing_time(monday_before_opening)).to eq(monday_closing)
174
+ expect(advance_to_closing_time(monday_closing)).to eq(tuesday_closing)
175
+ end
176
+
177
+ context 'moving between timespans' do
178
+ before do
179
+ WorkingHours::Config.working_hours = {
180
+ mon: {'07:00' => '12:00', '13:00' => '18:00'},
181
+ tue: {'09:00' => '17:00'},
182
+ wed: {'09:00' => '17:00'},
183
+ thu: {'09:00' => '17:00'},
184
+ fri: {'09:00' => '17:00'}
185
+ }
186
+ end
187
+
188
+ let(:monday_morning) { Time.utc(2014, 4, 7, 10) }
189
+ let(:morning_closing) { Time.utc(2014, 4, 7, 12) }
190
+ let(:afternoon_closing) { Time.utc(2014, 4, 7, 18) }
191
+ let(:monday_break) { Time.utc(2014, 4, 7, 12) }
192
+ let(:tuesday_closing) { Time.utc(2014, 4, 8, 17) }
193
+
194
+ it 'moves from morning to end of morning slot' do
195
+ expect(advance_to_closing_time(monday_morning)).to eq(morning_closing)
196
+ end
197
+
198
+ it 'moves from break time to end of afternoon slot' do
199
+ expect(advance_to_closing_time(monday_break)).to eq(afternoon_closing)
200
+ end
201
+
202
+ it 'moves from afternoon closing slot to next day' do
203
+ expect(advance_to_closing_time(afternoon_closing)).to eq(tuesday_closing)
204
+ end
205
+ end
206
+
207
+ context 'supporting midnight' do
208
+ before do
209
+ WorkingHours::Config.working_hours = {
210
+ mon: {'00:00' => '24:00'},
211
+ tue: {'09:00' => '17:00'}
212
+ }
213
+ end
214
+
215
+ let(:monday_morning) { Time.utc(2014, 4, 7, 0) }
216
+ let(:monday_closing) { Time.utc(2014, 4, 7) + 86399.999999 }
217
+ let(:tuesday_closing) { Time.utc(2014, 4, 8, 17) }
218
+ let(:sunday) { Time.utc(2014, 4, 6, 17) }
219
+
220
+ it 'moves from morning to midnight' do
221
+ expect(advance_to_closing_time(monday_morning)).to eq(monday_closing)
222
+ end
223
+
224
+ it 'moves from midnight to end of next slot' do
225
+ expect(advance_to_closing_time(monday_closing)).to eq(tuesday_closing)
226
+ end
227
+
228
+ it 'moves over midnight' do
229
+ expect(advance_to_closing_time(sunday)).to eq(monday_closing)
230
+ end
231
+ end
232
+
233
+ it 'works with any input timezone (converts to config)' do
234
+ # Monday 0 am (-09:00) is 9am in UTC time, working time!
235
+ monday_morning = Time.new(2014, 4, 7, 0, 0, 0 , "-09:00")
236
+ monday_closing = Time.new(2014, 4, 7, 12, 0, 0 , "-05:00")
237
+ monday_night = Time.new(2014, 4, 7, 22, 0, 0, "+02:00")
238
+ tuesday_evening = Time.utc(2014, 4, 8, 17)
239
+ expect(advance_to_closing_time(monday_morning)).to eq(monday_closing)
240
+ expect(advance_to_closing_time(monday_night)).to eq(tuesday_evening)
241
+ end
242
+
243
+ it 'returns time in config zone' do
244
+ WorkingHours::Config.time_zone = 'Tokyo'
245
+ expect(advance_to_closing_time(Time.new(2014, 4, 7, 0, 0, 0)).zone).to eq('JST')
246
+ end
247
+ end
248
+
249
+ describe '#next_working_time' do
250
+
251
+ it 'jumps non-working day' do
252
+ WorkingHours::Config.holidays = [Date.new(2014, 5, 1)]
253
+ holiday = Time.utc(2014, 5, 1, 12, 0)
254
+ sunday = Time.utc(2014, 6, 1, 12, 0)
255
+ expect(next_working_time(holiday)).to eq(Time.utc(2014, 5, 2, 9, 0))
256
+ expect(next_working_time(sunday)).to eq(Time.utc(2014, 6, 2, 9, 0))
257
+ end
258
+
259
+ it 'moves to the following timespan during working hours' do
260
+ monday = Time.utc(2014, 4, 7, 12, 0)
261
+ tuesday = Time.utc(2014, 4, 8, 9, 0)
262
+ expect(next_working_time(monday)).to eq(tuesday)
263
+ end
264
+
265
+ it 'jumps outside working hours' do
266
+ monday_before_opening = Time.utc(2014, 4, 7, 8, 59)
267
+ monday_opening = Time.utc(2014, 4, 7, 9, 0)
268
+ monday_closing = Time.utc(2014, 4, 7, 17, 0)
269
+ tuesday_opening = Time.utc(2014, 4, 8, 9, 0)
270
+ expect(next_working_time(monday_before_opening)).to eq(monday_opening)
271
+ expect(next_working_time(monday_closing)).to eq(tuesday_opening)
272
+ end
273
+
274
+ context 'move between timespans' do
275
+ before do
276
+ WorkingHours::Config.working_hours = {
277
+ mon: {'07:00' => '12:00', '13:00' => '18:00'},
278
+ tue: {'09:00' => '17:00'},
279
+ wed: {'09:00' => '17:00'},
280
+ thu: {'09:00' => '17:00'},
281
+ fri: {'09:00' => '17:00'}
282
+ }
283
+ end
284
+
285
+ let(:monday_morning) { Time.utc(2014, 4, 7, 10) }
286
+ let(:monday_afternoon) { Time.utc(2014, 4, 7, 13) }
287
+ let(:monday_break) { Time.utc(2014, 4, 7, 12) }
288
+ let(:tuesday_morning) { Time.utc(2014, 4, 8, 9) }
289
+
290
+ it 'moves from morning to afternoon slot' do
291
+ expect(next_working_time(monday_morning)).to eq(monday_afternoon)
292
+ end
293
+
294
+ it 'moves from break time to afternoon slot' do
295
+ expect(next_working_time(monday_break)).to eq(monday_afternoon)
296
+ end
297
+
298
+ it 'moves from afternoon slot to next day' do
299
+ expect(next_working_time(monday_afternoon)).to eq(tuesday_morning)
300
+ end
301
+ end
302
+
303
+ it 'works with any input timezone (converts to config)' do
304
+ # Monday 0 am (-09:00) is 9am in UTC time, working time!
305
+ monday_morning = Time.new(2014, 4, 7, 0, 0, 0 , "-09:00")
306
+ monday_night = Time.new(2014, 4, 7, 22, 0, 0, "+02:00")
307
+ tuesday_morning = Time.utc(2014, 4, 8, 9)
308
+ expect(next_working_time(monday_morning)).to eq(tuesday_morning)
309
+ expect(next_working_time(monday_night)).to eq(tuesday_morning)
310
+ end
311
+
312
+ it 'returns time in config zone' do
313
+ WorkingHours::Config.time_zone = 'Tokyo'
314
+ expect(next_working_time(Time.new(2014, 4, 7, 0, 0, 0)).zone).to eq('JST')
315
+ end
316
+ end
317
+
151
318
  describe '#return_to_working_time' do
152
319
  it 'jumps non-working day' do
153
320
  WorkingHours::Config.holidays = [Date.new(2014, 5, 1)]
@@ -62,6 +62,10 @@ describe WorkingHours::Duration do
62
62
  WorkingHours::Config.time_zone = 'Tokyo'
63
63
  expect(7.working.days.from_now.zone).to eq('JST')
64
64
  end
65
+
66
+ it 'should not hang with fractional hours' do
67
+ WorkingHours::Duration.new(4.1, :hours).since(Time.utc(1991, 11, 15, 21))
68
+ end
65
69
  end
66
70
 
67
71
  describe '#until' do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: working_hours
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adrien Jarthon
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-08-18 00:00:00.000000000 Z
12
+ date: 2015-12-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -154,7 +154,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
154
154
  version: '0'
155
155
  requirements: []
156
156
  rubyforge_project:
157
- rubygems_version: 2.2.3
157
+ rubygems_version: 2.4.5.1
158
158
  signing_key:
159
159
  specification_version: 4
160
160
  summary: time calculation with working hours
@@ -167,3 +167,4 @@ test_files:
167
167
  - spec/working_hours/duration_proxy_spec.rb
168
168
  - spec/working_hours/duration_spec.rb
169
169
  - spec/working_hours_spec.rb
170
+ has_rdoc: