tempr 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.markdown +14 -0
- data/README.markdown +12 -1
- data/lib/tempr/date_time_range.rb +79 -21
- data/lib/tempr/version.rb +1 -1
- data/test/each_time_of_day.rb +94 -0
- data/test/suite.rb +1 -1
- data/test/time_subrange.rb +2 -2
- metadata +6 -5
- data/test/at_time.rb +0 -36
data/CHANGELOG.markdown
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
## 0.1.1 / 2012-02-18
|
4
|
+
|
5
|
+
- add `SubRangeIterator#cover?` shortcut
|
6
|
+
- add `between_times`
|
7
|
+
- `on_day` renamed `each_day_of_month`; deprecation warning
|
8
|
+
- `at_time` renamed `each_time_of_day`; deprecation warning
|
9
|
+
- add utc_offset param to `each_time_of_day`, `time_range`
|
10
|
+
- fix error where time subranges forced to local time
|
11
|
+
|
12
|
+
## 0.1.0 / 2012-02-16
|
13
|
+
|
14
|
+
- Initial gem release
|
data/README.markdown
CHANGED
@@ -2,4 +2,15 @@
|
|
2
2
|
## a Ruby temporal expressions library
|
3
3
|
|
4
4
|
|
5
|
-
This is a work in progress. See date_time_range.rb for usage examples.
|
5
|
+
This is a work in progress. See date_time_range.rb for usage examples.
|
6
|
+
|
7
|
+
|
8
|
+
### License:
|
9
|
+
|
10
|
+
Copyright (c) 2012 Eric Gjertsen
|
11
|
+
|
12
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
13
|
+
|
14
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@@ -103,9 +103,9 @@ module Tempr
|
|
103
103
|
build_subrange do |s|
|
104
104
|
s.step = n
|
105
105
|
s.adjust_range { |r| time_range(r) }
|
106
|
-
s.offset { |tm| tm
|
107
|
-
s.increment { |tm,i| tm
|
108
|
-
s.span { |tm| tm
|
106
|
+
s.offset { |tm| tm + offset }
|
107
|
+
s.increment { |tm,i| tm + i }
|
108
|
+
s.span { |tm| tm + dur }
|
109
109
|
end
|
110
110
|
end
|
111
111
|
alias each_second each_seconds
|
@@ -353,7 +353,7 @@ module Tempr
|
|
353
353
|
#
|
354
354
|
# if no +dur+ parameter passed,
|
355
355
|
# "every +nday+th day of the month, grouped into one-day intervals"
|
356
|
-
def
|
356
|
+
def each_day_of_month(nday,dur=1)
|
357
357
|
build_subrange do |s|
|
358
358
|
s.step = 1
|
359
359
|
s.adjust_range { |r| day_range(r) }
|
@@ -366,28 +366,61 @@ module Tempr
|
|
366
366
|
end
|
367
367
|
end
|
368
368
|
|
369
|
+
def on_day(nday,dur=1)
|
370
|
+
warn "Note #on_day is deprecated and will be removed in 0.2.0; use #each_day_of_month instead"
|
371
|
+
each_day_of_month(nday,dur)
|
372
|
+
end
|
373
|
+
|
369
374
|
# time-of-day iterator:
|
370
|
-
# "every day at +tm+, grouped into +dur+ second intervals"
|
375
|
+
# "every day at +tm+, grouped into +dur+ second intervals, in +utc_offset+"
|
371
376
|
#
|
372
|
-
# +tm+ is any string that can be Time.parse'd
|
377
|
+
# +tm+ is any string that can be Time.parse'd - relative to the local time and zone.
|
378
|
+
# (Note the date portion is ignored, if given.)
|
373
379
|
#
|
374
|
-
# if no +dur+
|
375
|
-
|
380
|
+
# if no +dur+ passed, intervals are 'instantaneous' time ranges
|
381
|
+
# if no +utc_offset+ passed, process-local timezone is used.
|
382
|
+
def each_time_of_day(tm,dur=0,utc_offset=nil)
|
376
383
|
tm_p = Time.parse(tm)
|
377
384
|
build_subrange do |s|
|
378
385
|
s.step = 60*60*24
|
379
|
-
s.adjust_range { |r| time_range(r) }
|
380
|
-
s.offset do |
|
386
|
+
s.adjust_range { |r| time_range(r,utc_offset) }
|
387
|
+
s.offset do |t|
|
381
388
|
Time.new(
|
382
|
-
|
383
|
-
tm_p.hour, tm_p.min, tm_p.sec,
|
389
|
+
t.year, t.month, t.day,
|
390
|
+
tm_p.hour, tm_p.min, tm_p.sec,
|
391
|
+
(t + s.step).utc_offset
|
384
392
|
)
|
385
393
|
end
|
386
|
-
s.increment { |
|
387
|
-
s.span { |
|
394
|
+
s.increment { |t,i| t + i }
|
395
|
+
s.span { |t| t + dur }
|
388
396
|
end
|
389
397
|
end
|
390
|
-
|
398
|
+
|
399
|
+
def at_time(tm,dur=0,utc_offset=nil)
|
400
|
+
warn "Note #at_time is deprecated and will be removed in 0.2.0; use #each_time_of_day instead"
|
401
|
+
each_time_of_day(tm,dur,utc_offset)
|
402
|
+
end
|
403
|
+
|
404
|
+
# time-of-day iterator specifying time range:
|
405
|
+
# "every day between +tm0+ and +tm1+, in +utc_offset+"
|
406
|
+
#
|
407
|
+
# parameters are any string that can be Time.parse'd - relative to the local time and zone.
|
408
|
+
# (Note the date portion is ignored, if given.)
|
409
|
+
#
|
410
|
+
# if +tm1+ < +tm0+, ranges are interpreted to go into the next day, e.g.
|
411
|
+
# `between_times "23:00", "01:00"`
|
412
|
+
def between_times(tm0,tm1,utc_offset=nil)
|
413
|
+
tm0_p = Time.parse(tm0)
|
414
|
+
tm1_p = Time.parse(tm1)
|
415
|
+
dur = if tm0_p <= tm1_p
|
416
|
+
tm1_p - tm0_p
|
417
|
+
else
|
418
|
+
dur = 60*60*24 - (tm0_p - tm1_p)
|
419
|
+
end
|
420
|
+
each_time_of_day(tm0, dur, utc_offset)
|
421
|
+
end
|
422
|
+
|
423
|
+
|
391
424
|
# ---
|
392
425
|
|
393
426
|
# Helper methods - these are a bit hacky and possibly buggy.
|
@@ -415,17 +448,28 @@ module Tempr
|
|
415
448
|
|
416
449
|
# unless already a time range,
|
417
450
|
# convert to exclusive date range, and then to time range
|
451
|
+
#
|
452
|
+
# Times are local time unless +utc_offset+ is passed
|
453
|
+
#
|
418
454
|
# For example,
|
419
455
|
#
|
420
|
-
# `2012-02-01..2012-02-29`
|
421
|
-
# `2012-02-01 00:00:00
|
456
|
+
# `time_range(2012-02-01..2012-02-29,'00:00')`
|
457
|
+
# #=> `2012-02-01 00:00:00 +00:00...2012-03-01 00:00:00 +00:00`
|
422
458
|
#
|
423
|
-
def time_range(rng=self)
|
459
|
+
def time_range(rng=self,utc_offset=nil)
|
424
460
|
if rng.begin.respond_to?(:sec) && rng.end.respond_to?(:sec)
|
425
|
-
rng.
|
461
|
+
utc_offset ||= rng.begin.utc_offset
|
462
|
+
Range.new( rng.begin.getlocal(utc_offset),
|
463
|
+
rng.end.getlocal(utc_offset),
|
464
|
+
rng.respond_to?(:exclude_end?) && rng.exclude_end?
|
465
|
+
)
|
426
466
|
else
|
427
467
|
adj_rng = day_range(rng)
|
428
|
-
|
468
|
+
b,e = adj_rng.begin, adj_rng.end
|
469
|
+
Range.new( Time.new(b.year,b.month,b.day,0,0,0,utc_offset),
|
470
|
+
Time.new(e.year,e.month,e.day,0,0,0,utc_offset),
|
471
|
+
true
|
472
|
+
)
|
429
473
|
end
|
430
474
|
end
|
431
475
|
|
@@ -511,6 +555,10 @@ module Tempr
|
|
511
555
|
self
|
512
556
|
end
|
513
557
|
|
558
|
+
def cover?(dt)
|
559
|
+
any? {|r| r.cover?(dt)}
|
560
|
+
end
|
561
|
+
|
514
562
|
# Recursive madness...
|
515
563
|
# note this could possibly use cached results stored by #all method,
|
516
564
|
# similar to Sequel
|
@@ -593,8 +641,18 @@ if $0 == __FILE__
|
|
593
641
|
require 'pp'
|
594
642
|
|
595
643
|
range = (Date.civil(2012,1,1)...Date.civil(2013,1,1)).extend(Tempr::DateTimeRange)
|
596
|
-
subrange = range.each_month.thursday(2).
|
644
|
+
subrange = range.each_month.thursday(2).each_time_of_day('2:00pm',60*60)
|
597
645
|
|
646
|
+
puts "base range time_range"
|
647
|
+
pp range.time_range(range,"+00:00")
|
648
|
+
|
598
649
|
pp subrange.to_a
|
650
|
+
puts
|
651
|
+
|
652
|
+
subrange2 = range.each_month.thursday(2).between_times('2:00pm','3:00pm')
|
653
|
+
|
654
|
+
puts "between_times"
|
655
|
+
pp subrange2.to_a
|
656
|
+
puts
|
599
657
|
|
600
658
|
end
|
data/lib/tempr/version.rb
CHANGED
@@ -0,0 +1,94 @@
|
|
1
|
+
require File.expand_path('test_helper', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
module EachTimeOfDayTests
|
4
|
+
module Fixtures
|
5
|
+
|
6
|
+
BaseRanges = {:year => Date.civil(2012,01,01)...
|
7
|
+
Date.civil(2013,01,01)
|
8
|
+
}
|
9
|
+
|
10
|
+
end
|
11
|
+
|
12
|
+
describe 'DateTimeRange#each_time_of_day' do
|
13
|
+
|
14
|
+
describe "specified time zone" do
|
15
|
+
let(:subject) { Fixtures::BaseRanges[:year].extend(Tempr::DateTimeRange) }
|
16
|
+
let(:offset_string) { '+09:00' }
|
17
|
+
let(:offset) { 9*60*60 }
|
18
|
+
|
19
|
+
it 'subranges should have the specified timezone offset' do
|
20
|
+
subject.each_day.each_time_of_day("11:20pm",60*60,offset_string).each do |range|
|
21
|
+
assert_equal offset, range.begin.utc_offset
|
22
|
+
assert_equal offset, range.end.utc_offset
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "across daylight savings time boundaries" do
|
28
|
+
let(:subject) { Fixtures::BaseRanges[:year].extend(Tempr::DateTimeRange) }
|
29
|
+
let(:time_string) { "2:00pm" }
|
30
|
+
let(:begin_hour_min) { [14,0] }
|
31
|
+
let(:end_hour_min) { [15,0] }
|
32
|
+
|
33
|
+
it 'should be at the same time of day regardless of time zone' do
|
34
|
+
subject.each_day.each_time_of_day(time_string,60*60).each do |range|
|
35
|
+
offset = range.begin.utc_offset
|
36
|
+
actual_begin = range.begin.getlocal(offset)
|
37
|
+
actual_end = range.end.getlocal(offset)
|
38
|
+
#puts "#{range.inspect}"
|
39
|
+
assert_equal begin_hour_min,
|
40
|
+
[actual_begin.hour, actual_begin.min],
|
41
|
+
"for range: #{range}"
|
42
|
+
assert_equal end_hour_min,
|
43
|
+
[actual_end.hour, actual_end.min],
|
44
|
+
"for range: #{range}"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
describe 'DateTimeRange#between_times' do
|
53
|
+
|
54
|
+
let(:subject) { Fixtures::BaseRanges[:year].extend(Tempr::DateTimeRange) }
|
55
|
+
|
56
|
+
def assert_range_matches( exp_begin, exp_end, range )
|
57
|
+
offset = range.begin.utc_offset
|
58
|
+
actual_begin = range.begin.getlocal(offset)
|
59
|
+
actual_end = range.end.getlocal(offset)
|
60
|
+
assert_equal exp_begin,
|
61
|
+
[actual_begin.hour, actual_begin.min],
|
62
|
+
"for range: #{range}"
|
63
|
+
assert_equal exp_end,
|
64
|
+
[actual_end.hour, actual_end.min],
|
65
|
+
"for range: #{range}"
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'should return correct ranges within a single day' do
|
69
|
+
begin_hour_min = [16,45]
|
70
|
+
end_hour_min = [19,35]
|
71
|
+
begin_string = "#{begin_hour_min[0]}:#{begin_hour_min[1]}"
|
72
|
+
end_string = "#{end_hour_min[0]}:#{end_hour_min[1]}"
|
73
|
+
|
74
|
+
subject.each_day.between_times(begin_string, end_string).each do |range|
|
75
|
+
assert_range_matches begin_hour_min, end_hour_min, range
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'should return correct ranges across days' do
|
80
|
+
begin_hour_min = [23,30]
|
81
|
+
end_hour_min = [02,17]
|
82
|
+
begin_string = "#{begin_hour_min[0]}:#{begin_hour_min[1]}"
|
83
|
+
end_string = "#{end_hour_min[0]}:#{end_hour_min[1]}"
|
84
|
+
|
85
|
+
subject.each_day.between_times(begin_string, end_string).each do |range|
|
86
|
+
assert_range_matches begin_hour_min, end_hour_min, range
|
87
|
+
assert_equal 1, (range.end.to_date - range.begin.to_date),
|
88
|
+
"for range: #{range}"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
end # namespace
|
data/test/suite.rb
CHANGED
data/test/time_subrange.rb
CHANGED
@@ -215,7 +215,7 @@ module TimeSubRangeTests
|
|
215
215
|
last_result
|
216
216
|
end
|
217
217
|
|
218
|
-
it '
|
218
|
+
it 'each_hours must return ranges starting up to 23:00:00 of the end date' do
|
219
219
|
last_result = subject.each_hours.to_a.last
|
220
220
|
assert_equal ( (Fixtures::ExclusiveDateRange.end.to_time - 60*60)...
|
221
221
|
Fixtures::ExclusiveDateRange.end.to_time ),
|
@@ -242,7 +242,7 @@ module TimeSubRangeTests
|
|
242
242
|
last_result
|
243
243
|
end
|
244
244
|
|
245
|
-
it '
|
245
|
+
it 'each_hours must return ranges starting up to 23:00:00 of the end date + 1' do
|
246
246
|
last_result = subject.each_hours.to_a.last
|
247
247
|
assert_equal ( ((Fixtures::NonExclusiveDateRange.end+1).to_time - 60*60)...
|
248
248
|
(Fixtures::NonExclusiveDateRange.end+1).to_time ),
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tempr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-02-
|
12
|
+
date: 2012-02-19 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: minitest
|
16
|
-
requirement: &
|
16
|
+
requirement: &10703460 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,7 +21,7 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *10703460
|
25
25
|
description: ''
|
26
26
|
email:
|
27
27
|
- ericgj72@gmail.com
|
@@ -30,12 +30,13 @@ extensions: []
|
|
30
30
|
extra_rdoc_files: []
|
31
31
|
files:
|
32
32
|
- .gitignore
|
33
|
+
- CHANGELOG.markdown
|
33
34
|
- Gemfile
|
34
35
|
- README.markdown
|
35
36
|
- lib/tempr.rb
|
36
37
|
- lib/tempr/date_time_range.rb
|
37
38
|
- lib/tempr/version.rb
|
38
|
-
- test/
|
39
|
+
- test/each_time_of_day.rb
|
39
40
|
- test/suite.rb
|
40
41
|
- test/test_helper.rb
|
41
42
|
- test/time_subrange.rb
|
data/test/at_time.rb
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
require File.expand_path('test_helper', File.dirname(__FILE__))
|
2
|
-
|
3
|
-
module AtTimeTests
|
4
|
-
module Fixtures
|
5
|
-
|
6
|
-
BaseRanges = {:local => Time.parse('2012-01-01 00:00:00 -0500')...
|
7
|
-
Time.parse('2013-01-01 00:00:00 -0500'),
|
8
|
-
:utc => Time.parse('2012-01-01 00:00:00 UTC')...
|
9
|
-
Time.parse('2013-01-01 00:00:00 UTC')
|
10
|
-
}
|
11
|
-
|
12
|
-
end
|
13
|
-
|
14
|
-
describe 'DateTimeRange#at_time' do
|
15
|
-
|
16
|
-
[:local, :utc].each do |time_type|
|
17
|
-
|
18
|
-
describe "across daylight savings time boundaries for #{time_type} times" do
|
19
|
-
|
20
|
-
let(:subject) { Fixtures::BaseRanges[time_type].extend(Tempr::DateTimeRange) }
|
21
|
-
|
22
|
-
it 'should be at the same time of day regardless of time zone' do
|
23
|
-
subject.each_day.at_time("2:00pm",60*60).each do |range|
|
24
|
-
offset = range.begin.utc_offset
|
25
|
-
actual = range.begin.getlocal(offset).hour
|
26
|
-
#puts "#{range}"
|
27
|
-
assert_equal 14, actual, "for range: #{range}"
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
end
|
32
|
-
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
end # namespace
|