time_math2 0.0.5 → 0.0.6
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 +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
|