time_math2 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +2 -7
- data/lib/time_math/resamplers.rb +1 -1
- data/lib/time_math/sequence.rb +10 -11
- data/lib/time_math/units/base.rb +12 -65
- data/lib/time_math/units/month.rb +4 -4
- data/lib/time_math/units/week.rb +1 -1
- data/lib/time_math/units/year.rb +3 -3
- data/lib/time_math/util.rb +43 -0
- data/lib/time_math/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 51045d4f122c5237a82ef69caa42a16680a61e53
|
4
|
+
data.tar.gz: 3efbc480f4aa87b64b07219746f647101b706372
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3a607d28b91d01cb76d1764564cd7e4cb04a57f994ed4931402b1d6625348ce4042e75fb60c9dd9043f0b5bda5a2b81a15149c9d6668d68be7ed97724d136acc
|
7
|
+
data.tar.gz: e6f66d0e085b1dd0ac4bb1fc57e94dd949a403a6f09a6242da4444285af99eefd158f0229a03d26e3b31714b208c65dfc11e59ee1a89d46012dbdad03fa9c9d3
|
data/CHANGELOG.md
CHANGED
@@ -1,7 +1,15 @@
|
|
1
1
|
# TimeMath Changelog
|
2
2
|
|
3
|
+
# 0.0.6 (2016-12-14)
|
4
|
+
|
5
|
+
* Fix approach to timezone info preservation (previously, it was clear bug, emerging from
|
6
|
+
false believing of how `Time.mktime` works). Thanks, @wojtha, for pointing to the problem.
|
7
|
+
* Add `#each` and `Enumerable` to `Sequence` (no idea why it wasn't done from the very
|
8
|
+
beginning). Again: thanks, @wojtha!
|
9
|
+
|
3
10
|
# 0.0.5 (2016-06-25)
|
4
11
|
|
12
|
+
* Add support for `Date`;
|
5
13
|
* Add optional second argument to rounding functions (`floor`, `ceil` and
|
6
14
|
so on), for "floor to 3-hour mark";
|
7
15
|
* Allow this argument, as well as in `advance`/`decrease`, to be non-integer;
|
data/README.md
CHANGED
@@ -35,7 +35,7 @@ Rails or without it, for any purpose.
|
|
35
35
|
* No monkey-patching of core classes (now **strict**; previously existing opt-in
|
36
36
|
core ext removed in 0.0.5);
|
37
37
|
* Works with Time, Date and DateTime;
|
38
|
-
* Accurately preserves timezone
|
38
|
+
* Accurately preserves timezone offset;
|
39
39
|
* Simple arithmetics: floor/ceil/round to any time unit (second, hour, year
|
40
40
|
or whatnot), advance/decrease by any unit;
|
41
41
|
* Chainable [operations](#set-of-operations-as-a-value-object), including
|
@@ -306,12 +306,7 @@ it means:
|
|
306
306
|
|
307
307
|
## Compatibility notes
|
308
308
|
|
309
|
-
TimeMath is known to work on MRI Ruby >=
|
310
|
-
|
311
|
-
On JRuby it works, too, though there could be _slightly_ unexpected results,
|
312
|
-
when JRuby fails to create time by timezone name (see [bug](https://github.com/jruby/jruby/issues/3978)).
|
313
|
-
TimeMath in this case fallbacks to the same solution that used for `DateTime`,
|
314
|
-
and at least preserves utc offset.
|
309
|
+
TimeMath is known to work on MRI Ruby >= 2.0 and JRuby >= 9.0.0.0.
|
315
310
|
|
316
311
|
On Rubinius, some of tests fail and I haven't time to investigate it. If
|
317
312
|
somebody still uses Rubinius and wants TimeMath to be working properly
|
data/lib/time_math/resamplers.rb
CHANGED
@@ -62,7 +62,7 @@ module TimeMath
|
|
62
62
|
|
63
63
|
sequence.ranges.map do |r|
|
64
64
|
values = @hash.select { |k, _| r.cover?(k) }.map(&:last)
|
65
|
-
values = block.call(values) if block
|
65
|
+
values = block.call(values) if block
|
66
66
|
[r.begin, values]
|
67
67
|
end.to_h
|
68
68
|
end
|
data/lib/time_math/sequence.rb
CHANGED
@@ -230,26 +230,25 @@ module TimeMath
|
|
230
230
|
end
|
231
231
|
end
|
232
232
|
|
233
|
-
#
|
234
|
-
#
|
235
|
-
#
|
236
|
-
# unless sequence is not set to floor values.
|
233
|
+
# Enumerates time unit between `from` and `to`. They will have same granularity as from
|
234
|
+
# (e.g. if `unit` is day and from is 2016-05-01 13:30, each of return values will be next
|
235
|
+
# day at 13:30), unless sequence is not set to floor values.
|
237
236
|
#
|
238
|
-
# @return [
|
239
|
-
def
|
240
|
-
|
237
|
+
# @return [Enumerator<Time, or Date, or DateTime>]
|
238
|
+
def each
|
239
|
+
return to_enum(:each) unless block_given?
|
241
240
|
|
242
241
|
iter = from
|
243
242
|
while iter < to
|
244
|
-
|
243
|
+
yield(op.call(iter))
|
245
244
|
|
246
245
|
iter = unit.advance(iter)
|
247
246
|
end
|
248
|
-
|
249
|
-
|
250
|
-
op.call(seq)
|
247
|
+
yield(op.call(to)) unless exclude_end?
|
251
248
|
end
|
252
249
|
|
250
|
+
include Enumerable
|
251
|
+
|
253
252
|
# Creates an array of pairs (time unit start, time unit end) between
|
254
253
|
# from and to.
|
255
254
|
#
|
data/lib/time_math/units/base.rb
CHANGED
@@ -46,8 +46,8 @@ module TimeMath
|
|
46
46
|
# @param tm [Time,Date,DateTime] time value to floor.
|
47
47
|
# @param span [Numeric] how many units to floor to. For units
|
48
48
|
# less than week supports float/rational values.
|
49
|
-
# @return [Time,Date,DateTime] floored time value; class and timezone
|
50
|
-
#
|
49
|
+
# @return [Time,Date,DateTime] floored time value; class and timezone offset of origin
|
50
|
+
# would be preserved.
|
51
51
|
def floor(tm, span = 1)
|
52
52
|
int_floor = advance(floor_1(tm), (tm.send(name) / span.to_f).floor * span - tm.send(name))
|
53
53
|
float_fix(tm, int_floor, span % 1)
|
@@ -61,7 +61,7 @@ module TimeMath
|
|
61
61
|
# @param tm [Time,Date,DateTime] time value to ceil.
|
62
62
|
# @param span [Numeric] how many units to ceil to. For units
|
63
63
|
# less than week supports float/rational values.
|
64
|
-
# @return [Time,Date,DateTime] ceiled time value; class and timezone
|
64
|
+
# @return [Time,Date,DateTime] ceiled time value; class and timezone offset
|
65
65
|
# of origin would be preserved.
|
66
66
|
def ceil(tm, span = 1)
|
67
67
|
f = floor(tm, span)
|
@@ -78,7 +78,7 @@ module TimeMath
|
|
78
78
|
# @param tm [Time,Date,DateTime] time value to round.
|
79
79
|
# @param span [Numeric] how many units to round to. For units
|
80
80
|
# less than week supports float/rational values.
|
81
|
-
# @return [Time,Date,DateTime] rounded time value; class and timezone
|
81
|
+
# @return [Time,Date,DateTime] rounded time value; class and timezone offset
|
82
82
|
# of origin would be preserved.
|
83
83
|
def round(tm, span = 1)
|
84
84
|
f, c = floor(tm, span), ceil(tm, span)
|
@@ -95,7 +95,7 @@ module TimeMath
|
|
95
95
|
# @param tm [Time,Date,DateTime] time value to calculate prev on.
|
96
96
|
# @param span [Numeric] how many units to floor to. For units
|
97
97
|
# less than week supports float/rational values.
|
98
|
-
# @return [Time,Date,DateTime] prev time value; class and timezone
|
98
|
+
# @return [Time,Date,DateTime] prev time value; class and timezone offset
|
99
99
|
# of origin would be preserved.
|
100
100
|
def prev(tm, span = 1)
|
101
101
|
f = floor(tm, span)
|
@@ -111,7 +111,7 @@ module TimeMath
|
|
111
111
|
# @param tm [Time,Date,DateTime] time value to calculate next on.
|
112
112
|
# @param span [Numeric] how many units to ceil to. For units
|
113
113
|
# less than week supports float/rational values.
|
114
|
-
# @return [Time,Date,DateTime] next time value; class and timezone
|
114
|
+
# @return [Time,Date,DateTime] next time value; class and timezone offset
|
115
115
|
# of origin would be preserved.
|
116
116
|
def next(tm, span = 1)
|
117
117
|
c = ceil(tm, span)
|
@@ -134,7 +134,7 @@ module TimeMath
|
|
134
134
|
# @param amount [Numeric] how many units forward to go. For units
|
135
135
|
# less than week supports float/rational values.
|
136
136
|
#
|
137
|
-
# @return [Time,Date,DateTime] advanced time value; class and timezone
|
137
|
+
# @return [Time,Date,DateTime] advanced time value; class and timezone offset
|
138
138
|
# of origin would be preserved.
|
139
139
|
def advance(tm, amount = 1)
|
140
140
|
return decrease(tm, -amount) if amount < 0
|
@@ -147,7 +147,7 @@ module TimeMath
|
|
147
147
|
# @param amount [Integer] how many units forward to go. For units
|
148
148
|
# less than week supports float/rational values.
|
149
149
|
#
|
150
|
-
# @return [Time,Date,DateTime] decrease time value; class and timezone
|
150
|
+
# @return [Time,Date,DateTime] decrease time value; class and timezone offset
|
151
151
|
# of origin would be preserved.
|
152
152
|
def decrease(tm, amount = 1)
|
153
153
|
return advance(tm, -amount) if amount < 0
|
@@ -300,59 +300,16 @@ module TimeMath
|
|
300
300
|
"#<#{self.class}>"
|
301
301
|
end
|
302
302
|
|
303
|
-
|
304
|
-
|
305
|
-
# all except :week
|
306
|
-
NATURAL_UNITS = [:year, :month, :day, :hour, :min, :sec].freeze
|
307
|
-
EMPTY_VALUES = [nil, 1, 1, 0, 0, 0].freeze
|
303
|
+
private
|
308
304
|
|
309
305
|
def index
|
310
|
-
NATURAL_UNITS.index(name) or
|
306
|
+
Util::NATURAL_UNITS.index(name) or
|
311
307
|
raise NotImplementedError, "Can not be used for #{name}"
|
312
308
|
end
|
313
309
|
|
314
|
-
def generate(tm, replacements = {})
|
315
|
-
hash_to_tm(tm, tm_to_hash(tm).merge(replacements))
|
316
|
-
end
|
317
|
-
|
318
|
-
def tm_to_hash(tm)
|
319
|
-
Hash[*NATURAL_UNITS.flat_map { |s| [s, tm.send(s)] }]
|
320
|
-
end
|
321
|
-
|
322
|
-
def hash_to_tm(origin, hash)
|
323
|
-
components = NATURAL_UNITS.map { |s| hash[s] || 0 }
|
324
|
-
new_from_components(origin, *components)
|
325
|
-
end
|
326
|
-
|
327
|
-
def new_from_components(origin, *components)
|
328
|
-
components = EMPTY_VALUES.zip(components).map { |d, c| c || d }
|
329
|
-
case origin
|
330
|
-
when Time
|
331
|
-
res = Time.mktime(*components.reverse, nil, nil, nil, origin.zone)
|
332
|
-
fix_no_zone(res, origin, *components)
|
333
|
-
when DateTime
|
334
|
-
DateTime.new(*components, origin.zone)
|
335
|
-
when Date
|
336
|
-
Date.new(*components.first(3))
|
337
|
-
else
|
338
|
-
raise ArgumentError, "Expected Time, Date or DateTime, got #{origin.class}"
|
339
|
-
end
|
340
|
-
end
|
341
|
-
|
342
|
-
def to_components(tm)
|
343
|
-
case tm
|
344
|
-
when Time, DateTime
|
345
|
-
[tm.year, tm.month, tm.day, tm.hour, tm.min, tm.sec]
|
346
|
-
when Date
|
347
|
-
[tm.year, tm.month, tm.day]
|
348
|
-
else
|
349
|
-
raise ArgumentError, "Expected Time, Date or DateTime, got #{tm.class}"
|
350
|
-
end
|
351
|
-
end
|
352
|
-
|
353
310
|
def floor_1(tm)
|
354
|
-
components =
|
355
|
-
|
311
|
+
components = Util.tm_to_array(tm).first(index + 1)
|
312
|
+
Util.array_to_tm(tm, *components)
|
356
313
|
end
|
357
314
|
|
358
315
|
def float_fix(tm, floored, float_span_part)
|
@@ -363,16 +320,6 @@ module TimeMath
|
|
363
320
|
float_floored > tm ? floored : float_floored
|
364
321
|
end
|
365
322
|
end
|
366
|
-
|
367
|
-
def fix_no_zone(tm, origin, *components)
|
368
|
-
if origin.zone != 'UTC' && tm.zone == 'UTC'
|
369
|
-
# Fixes things like this one: https://github.com/jruby/jruby/issues/3978
|
370
|
-
# ...by falling back to use of UTC offset instead of timezone abbr
|
371
|
-
Time.new(*components, origin.utc_offset)
|
372
|
-
else
|
373
|
-
tm
|
374
|
-
end
|
375
|
-
end
|
376
323
|
end
|
377
324
|
end
|
378
325
|
end
|
@@ -17,16 +17,16 @@ module TimeMath
|
|
17
17
|
protected
|
18
18
|
|
19
19
|
def _succ(tm)
|
20
|
-
return
|
20
|
+
return Util.merge(tm, year: tm.year + 1, month: 1) if tm.month == 12
|
21
21
|
|
22
|
-
t =
|
22
|
+
t = Util.merge(tm, month: tm.month + 1)
|
23
23
|
fix_month(t, t.month + 1)
|
24
24
|
end
|
25
25
|
|
26
26
|
def _prev(tm)
|
27
|
-
return
|
27
|
+
return Util.merge(tm, year: tm.year - 1, month: 12) if tm.month == 1
|
28
28
|
|
29
|
-
t =
|
29
|
+
t = Util.merge(tm, month: tm.month - 1)
|
30
30
|
fix_month(t, t.month - 1)
|
31
31
|
end
|
32
32
|
|
data/lib/time_math/units/week.rb
CHANGED
@@ -11,7 +11,7 @@ module TimeMath
|
|
11
11
|
raise NotImplementedError, 'For now, week only can floor to one'
|
12
12
|
|
13
13
|
f = TimeMath.day.floor(tm)
|
14
|
-
extra_days = tm.wday
|
14
|
+
extra_days = tm.wday.zero? ? 6 : tm.wday - 1
|
15
15
|
TimeMath.day.decrease(f, extra_days)
|
16
16
|
end
|
17
17
|
|
data/lib/time_math/units/year.rb
CHANGED
@@ -7,7 +7,7 @@ module TimeMath
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def measure(from, to)
|
10
|
-
if
|
10
|
+
if Util.merge(from, year: to.year) < to
|
11
11
|
to.year - from.year
|
12
12
|
else
|
13
13
|
to.year - from.year - 1
|
@@ -17,11 +17,11 @@ module TimeMath
|
|
17
17
|
protected
|
18
18
|
|
19
19
|
def _advance(tm, steps)
|
20
|
-
|
20
|
+
Util.merge(tm, year: tm.year + steps.to_i)
|
21
21
|
end
|
22
22
|
|
23
23
|
def _decrease(tm, steps)
|
24
|
-
|
24
|
+
Util.merge(tm, year: tm.year - steps.to_i)
|
25
25
|
end
|
26
26
|
end
|
27
27
|
end
|
data/lib/time_math/util.rb
CHANGED
@@ -1,10 +1,53 @@
|
|
1
1
|
module TimeMath
|
2
2
|
# @private
|
3
3
|
module Util
|
4
|
+
# all except :week
|
5
|
+
NATURAL_UNITS = [:year, :month, :day, :hour, :min, :sec].freeze
|
6
|
+
EMPTY_VALUES = [nil, 1, 1, 0, 0, 0].freeze
|
7
|
+
|
4
8
|
module_function
|
5
9
|
|
6
10
|
def timey?(val)
|
7
11
|
[Time, DateTime, Date].any? { |cls| val.is_a?(cls) }
|
8
12
|
end
|
13
|
+
|
14
|
+
def merge(tm, attrs = {})
|
15
|
+
hash_to_tm(tm, tm_to_hash(tm).merge(attrs))
|
16
|
+
end
|
17
|
+
|
18
|
+
def array_to_tm(origin, *components)
|
19
|
+
components = EMPTY_VALUES.zip(components).map { |d, c| c || d }
|
20
|
+
|
21
|
+
case origin
|
22
|
+
when Time
|
23
|
+
Time.new(*components, origin.utc_offset)
|
24
|
+
when DateTime
|
25
|
+
DateTime.new(*components, origin.zone)
|
26
|
+
when Date
|
27
|
+
Date.new(*components.first(3))
|
28
|
+
else
|
29
|
+
raise ArgumentError, "Expected Time, Date or DateTime, got #{origin.class}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def tm_to_array(tm)
|
34
|
+
case tm
|
35
|
+
when Time, DateTime
|
36
|
+
[tm.year, tm.month, tm.day, tm.hour, tm.min, tm.sec]
|
37
|
+
when Date
|
38
|
+
[tm.year, tm.month, tm.day]
|
39
|
+
else
|
40
|
+
raise ArgumentError, "Expected Time, Date or DateTime, got #{tm.class}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def tm_to_hash(tm)
|
45
|
+
Hash[*NATURAL_UNITS.flat_map { |s| [s, tm.send(s)] }]
|
46
|
+
end
|
47
|
+
|
48
|
+
def hash_to_tm(origin, hash)
|
49
|
+
components = NATURAL_UNITS.map { |s| hash[s] || 0 }
|
50
|
+
array_to_tm(origin, *components)
|
51
|
+
end
|
9
52
|
end
|
10
53
|
end
|
data/lib/time_math/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: time_math2
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Victor Shepelev
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-12-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rubocop
|
@@ -158,7 +158,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
158
158
|
version: '0'
|
159
159
|
requirements: []
|
160
160
|
rubyforge_project:
|
161
|
-
rubygems_version: 2.
|
161
|
+
rubygems_version: 2.5.2
|
162
162
|
signing_key:
|
163
163
|
specification_version: 4
|
164
164
|
summary: Easy time math
|