timerage 2.1.1 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/timerage/time_interval.rb +38 -11
- data/lib/timerage/version.rb +1 -1
- data/lib/timerage.rb +16 -3
- data/spec/timerage/time_interval_spec.rb +43 -13
- data/spec/timerage_spec.rb +16 -0
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d21955bc8e1453cafb40e1de151e67835964f857728eaa1cf001a7c70a79a1fb
|
4
|
+
data.tar.gz: efc6d71d6fbc442b2fc3fa2066657cc51bc669549ad52a576ef09f14d29aa171
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 58064fee1d615adf865a0de63f0db64d7757af8b837c475d9ccf43018fd25574305250ef6ee525931ef9a7d5cdd1a69e203a13b4de22511ec9cafbc4e07a13e2
|
7
|
+
data.tar.gz: 836ed39bef1dd174aa19e90a9f049a5bff4c88a79419aaf810470a698cdee2fb44aa41f17624a95fb440ee7ed31fad4aa1fdc53ed7fad8bef20e5c00cba8bf15
|
@@ -5,11 +5,34 @@ module Timerage
|
|
5
5
|
class TimeInterval < Range
|
6
6
|
|
7
7
|
class << self
|
8
|
+
# Returns a new TimeInterval
|
9
|
+
#
|
10
|
+
# start_time - the beginning of the interval
|
11
|
+
# end_time - the end of the interval
|
12
|
+
# exclude_end - whether the end time is excluded from the interval
|
8
13
|
def new(*args)
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
14
|
+
return from_range(*args) if args.first.respond_to?(:exclude_end?)
|
15
|
+
|
16
|
+
super
|
17
|
+
end
|
18
|
+
|
19
|
+
# Returns a new TimeInterval
|
20
|
+
#
|
21
|
+
# time - the beginning or end of the interval
|
22
|
+
# duration - the duration of the interval, if negative the
|
23
|
+
# interval will start before`time`
|
24
|
+
# exclude_end - whether the end time is excluded from the interval
|
25
|
+
def from_time_and_duration(time, duration, exclude_end: true)
|
26
|
+
if duration >= 0
|
27
|
+
new(time, time + duration, exclude_end)
|
28
|
+
else
|
29
|
+
new(time + duration, time, exclude_end)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Returns a new TimeInterval based on the specified range
|
34
|
+
def from_range(range)
|
35
|
+
new(range.begin, range.end, range.exclude_end?)
|
13
36
|
end
|
14
37
|
end
|
15
38
|
|
@@ -32,12 +55,12 @@ module Timerage
|
|
32
55
|
end
|
33
56
|
end
|
34
57
|
|
35
|
-
def slice(
|
36
|
-
time_enumerator(
|
37
|
-
.map{|
|
38
|
-
|
39
|
-
|
40
|
-
|
58
|
+
def slice(duration)
|
59
|
+
time_enumerator(duration)
|
60
|
+
.each_cons(2).map { |s_begin, s_end| TimeInterval.new(s_begin, s_end, exclusive_end_slice?(s_end)) }
|
61
|
+
.then do |slices|
|
62
|
+
slices << TimeInterval.new(slices.last.end, self.end, exclusive_end_slice?(slices.last.end + duration)) if slices.present?
|
63
|
+
end
|
41
64
|
end
|
42
65
|
|
43
66
|
# Return new TimeInterval that is the concatenation of self and
|
@@ -134,8 +157,12 @@ module Timerage
|
|
134
157
|
an_obj.respond_to?(:end)
|
135
158
|
end
|
136
159
|
|
160
|
+
def exclusive_end_slice?(slice_end)
|
161
|
+
!((slice_end > self.end) && !exclude_end?)
|
162
|
+
end
|
163
|
+
|
137
164
|
def time_enumerator(step)
|
138
|
-
next_offset = 0
|
165
|
+
next_offset = step * 0
|
139
166
|
|
140
167
|
Enumerator.new do |y|
|
141
168
|
while self.cover?(self.begin + next_offset)
|
data/lib/timerage/version.rb
CHANGED
data/lib/timerage.rb
CHANGED
@@ -16,17 +16,30 @@ module Timerage
|
|
16
16
|
Time.iso8601(str)
|
17
17
|
end
|
18
18
|
|
19
|
+
# Returns a new TimeInterval from a time and duration or two times.
|
20
|
+
#
|
21
|
+
# signature:
|
22
|
+
# Interval(begin_time, end_time, exclude_end: true)
|
23
|
+
# Interval(begin_or_end_time, duration, exclude_end: true)
|
24
|
+
def self.Interval(begin_or_end_time, end_time_or_duration, exclude_end: true)
|
25
|
+
if end_time_or_duration.respond_to?(:since)
|
26
|
+
TimeInterval.from_time_and_duration(begin_or_end_time, end_time_or_duration, exclude_end: exclude_end)
|
27
|
+
else
|
28
|
+
TimeInterval.new(begin_or_end_time, end_time_or_duration, exclude_end)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
19
32
|
refine Range do
|
20
33
|
def step(n, &blk)
|
21
34
|
if self.begin.kind_of?(Time) || self.begin.kind_of?(Date)
|
22
|
-
Timerage::TimeInterval.
|
35
|
+
Timerage::TimeInterval.from_range(self).step(n, &blk)
|
23
36
|
else
|
24
37
|
super
|
25
38
|
end
|
26
39
|
end
|
27
40
|
|
28
41
|
def to_time_interval
|
29
|
-
Timerage::TimeInterval.
|
42
|
+
Timerage::TimeInterval.from_range(self)
|
30
43
|
end
|
31
44
|
end
|
32
45
|
end
|
@@ -40,7 +53,7 @@ module Kernel
|
|
40
53
|
thing
|
41
54
|
|
42
55
|
when ->(x) { x.respond_to? :exclude_end? }
|
43
|
-
Timerage::TimeInterval.
|
56
|
+
Timerage::TimeInterval.from_range(thing)
|
44
57
|
|
45
58
|
when ->(x) { x.respond_to? :to_str }
|
46
59
|
Timerage.parse_iso8601(thing.to_str)
|
@@ -6,10 +6,16 @@ describe Timerage::TimeInterval do
|
|
6
6
|
let(:duration) { 3600 }
|
7
7
|
|
8
8
|
describe "creation" do
|
9
|
-
specify { expect(described_class.new(now-1
|
10
|
-
|
11
|
-
specify { expect(described_class.new(now-1, now, true))
|
12
|
-
|
9
|
+
specify { expect(described_class.new(now-1.day, now))
|
10
|
+
.to be_kind_of(described_class).and eq now-1.day..now }
|
11
|
+
specify { expect(described_class.new(now-1.day, now, true))
|
12
|
+
.to be_kind_of(described_class).and eq now-1.day...now }
|
13
|
+
specify { expect(described_class.new(now-1.day, now, false ))
|
14
|
+
.to be_kind_of(described_class).and eq now-1.day..now }
|
15
|
+
|
16
|
+
it "support new(range) for backwards compatibility" do
|
17
|
+
expect(described_class.new((now-1.day)..now)).to eq (now-1.day)..now
|
18
|
+
end
|
13
19
|
end
|
14
20
|
|
15
21
|
describe ".iso8601" do
|
@@ -86,12 +92,12 @@ describe Timerage::TimeInterval do
|
|
86
92
|
specify { expect( interval & (interval.begin...interval.end) ).to eq interval.begin...interval.end }
|
87
93
|
specify { expect( interval & (interval.begin...interval.end-1) )
|
88
94
|
.to eq interval.begin...interval.end-1 }
|
89
|
-
specify { expect( described_class.new(interval.begin
|
90
|
-
.to eq described_class.new(interval.begin
|
95
|
+
specify { expect( described_class.new(interval.begin, interval.end-1) & interval )
|
96
|
+
.to eq described_class.new(interval.begin,interval.end-1) }
|
91
97
|
end
|
92
98
|
|
93
99
|
describe "==" do
|
94
|
-
specify { expect( described_class.
|
100
|
+
specify { expect( described_class.from_range(interval) == interval ).to be true }
|
95
101
|
specify { expect( described_class.new(interval.begin, interval.end) == interval ).to be true }
|
96
102
|
end
|
97
103
|
|
@@ -159,7 +165,7 @@ describe Timerage::TimeInterval do
|
|
159
165
|
end
|
160
166
|
|
161
167
|
context "exclusive end" do
|
162
|
-
subject(:interval) { described_class.
|
168
|
+
subject(:interval) { described_class.from_range(now-duration...now) }
|
163
169
|
|
164
170
|
specify { expect(interval.exclude_end?).to be true }
|
165
171
|
specify { expect(interval.cover? now).to be false }
|
@@ -187,33 +193,57 @@ describe Timerage::TimeInterval do
|
|
187
193
|
end
|
188
194
|
|
189
195
|
context "exclusive 0 length interval" do
|
190
|
-
subject(:interval) { described_class.
|
196
|
+
subject(:interval) { described_class.from_range(now...now) }
|
191
197
|
specify { expect{ |b| subject.step(1, &b) }.not_to yield_control }
|
192
198
|
end
|
193
199
|
|
194
200
|
context "inclusive 0 length interval" do
|
195
|
-
subject(:interval) { described_class.
|
201
|
+
subject(:interval) { described_class.from_range(now..now) }
|
196
202
|
specify { expect{ |b| subject.step(1, &b) }.to yield_control.once }
|
197
203
|
end
|
198
204
|
|
199
205
|
context "includes leap day" do
|
200
|
-
subject(:interval) { described_class.new(before_leap_day
|
206
|
+
subject(:interval) { described_class.new(before_leap_day, after_leap_day) }
|
201
207
|
specify { expect{ |b| subject.step(1.day, &b) }.to yield_control.exactly(3).times }
|
202
208
|
specify { expect{ |b| subject.step(86_400, &b) }.to yield_control.exactly(3).times }
|
203
209
|
end
|
204
210
|
|
205
211
|
context "transition into dst with explicit time zone" do
|
206
|
-
subject(:interval) { described_class.new(before_dst
|
212
|
+
subject(:interval) { described_class.new(before_dst, after_dst) }
|
207
213
|
specify { expect{ |b| subject.step(1.hour, &b) }.to yield_control.exactly(2).times }
|
208
214
|
specify { expect{ |b| subject.step(3_600, &b) }.to yield_control.exactly(2).times }
|
209
215
|
end
|
210
216
|
|
211
217
|
context "transition into dst without explicit time zone" do
|
212
|
-
subject(:interval) { described_class.new(before_dst
|
218
|
+
subject(:interval) { described_class.new(before_dst, (before_dst + 1.hour)) }
|
213
219
|
specify { expect{ |b| subject.step(1.hour, &b) }.to yield_control.exactly(2).times }
|
214
220
|
specify { expect{ |b| subject.step(3_600, &b) }.to yield_control.exactly(2).times }
|
215
221
|
end
|
216
222
|
|
223
|
+
context "When given date range" do
|
224
|
+
it "returns date objects when stepping through the range with a day duration" do
|
225
|
+
date_range = Date.new(2020, 1, 1)..Date.new(2020,1,3)
|
226
|
+
described_class.new(date_range).step(1.day) do |date|
|
227
|
+
expect(date).to be_kind_of Date
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
it "returns Time objects when stepping through the range with an hour duration" do
|
232
|
+
date_range = Date.new(2020, 1, 1)..Date.new(2020,1,2)
|
233
|
+
described_class.new(date_range).step(6.hours) do |date|
|
234
|
+
expect(date).to be_kind_of Time
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
context "produces complete slices" do
|
240
|
+
it "slices a range into intervals without missing any time inbetween" do
|
241
|
+
range = Timerage(Time.parse("2023-10-31T00:00:00+00:00")...Time.parse("2024-06-30 00:00:00 UTC"))
|
242
|
+
slices = range.slice(1.month)
|
243
|
+
expect(slices.map(&:duration).sum).to eq range.duration
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
217
247
|
let(:leap_day) { Time.parse("2016-02-29 12:00:00 UTC") }
|
218
248
|
let(:before_leap_day) { leap_day - 1.day }
|
219
249
|
let(:after_leap_day) { leap_day + 1.day}
|
data/spec/timerage_spec.rb
CHANGED
@@ -17,6 +17,22 @@ describe Timerage do
|
|
17
17
|
.to be_kind_of Time }
|
18
18
|
end
|
19
19
|
|
20
|
+
describe ".Interval" do
|
21
|
+
let(:t) { Time.now }
|
22
|
+
let(:one_day) { 1.day }
|
23
|
+
|
24
|
+
specify { expect(described_class.Interval(t, 1.day)).to eq t...(t+1.day) }
|
25
|
+
specify { expect(described_class.Interval(t, 1.day, exclude_end: false)).to eq(t..(t+1.day)) }
|
26
|
+
|
27
|
+
specify { expect(described_class.Interval(t, -1.day)).to eq((t-1.day)...t) }
|
28
|
+
specify { expect(described_class.Interval(t, -1.day, exclude_end: false)).to eq((t+-1.day)..t) }
|
29
|
+
|
30
|
+
specify { expect{ described_class.Interval(t, (t+1.day)).to eq(t...(t+1.day)) } }
|
31
|
+
specify { expect{ described_class.Interval(t, (t+1.day), exclude_end: false).to eq(t..(t+1.day)) } }
|
32
|
+
|
33
|
+
specify { expect{ described_class.Interval(t..(t+1.day)).to eq(t..(t+1.day)) } }
|
34
|
+
end
|
35
|
+
|
20
36
|
context "interval include end" do
|
21
37
|
specify { expect{|b| range.step(1200, &b) }
|
22
38
|
.to yield_successive_args now-duration, now-(duration-1200), now-(duration-2400), now }
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: timerage
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter Williams
|
8
8
|
- Chris Schneider
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2024-11-08 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -96,7 +96,7 @@ homepage: ''
|
|
96
96
|
licenses:
|
97
97
|
- MIT
|
98
98
|
metadata: {}
|
99
|
-
post_install_message:
|
99
|
+
post_install_message:
|
100
100
|
rdoc_options: []
|
101
101
|
require_paths:
|
102
102
|
- lib
|
@@ -111,8 +111,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
111
111
|
- !ruby/object:Gem::Version
|
112
112
|
version: '0'
|
113
113
|
requirements: []
|
114
|
-
rubygems_version: 3.
|
115
|
-
signing_key:
|
114
|
+
rubygems_version: 3.4.19
|
115
|
+
signing_key:
|
116
116
|
specification_version: 4
|
117
117
|
summary: Simple refinement to Range to allow Time or Date as arguments
|
118
118
|
test_files:
|