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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8fe3eec624d634487ddc4b74d08a3d39ec3f34d5
4
- data.tar.gz: 87c691b0990e5e4a03f7bad4602e8bf100d1d526
3
+ metadata.gz: 51045d4f122c5237a82ef69caa42a16680a61e53
4
+ data.tar.gz: 3efbc480f4aa87b64b07219746f647101b706372
5
5
  SHA512:
6
- metadata.gz: 8a7e17f5d2f9768c734649768b95c8ad63f168ca3c8686f2d52440caa952f8c7a20bc1af223cb5238eacfdec7e5924e814c0d8385887e83a5623da0024d15a55
7
- data.tar.gz: a39344389ba42191d780257d97e4c53e6e2e84a5512e7deac17ba731a543e5decab9e01e833b266dc6f93efbbdec1d11135deff8cb78110071535ef382c713a7
6
+ metadata.gz: 3a607d28b91d01cb76d1764564cd7e4cb04a57f994ed4931402b1d6625348ce4042e75fb60c9dd9043f0b5bda5a2b81a15149c9d6668d68be7ed97724d136acc
7
+ data.tar.gz: e6f66d0e085b1dd0ac4bb1fc57e94dd949a403a6f09a6242da4444285af99eefd158f0229a03d26e3b31714b208c65dfc11e59ee1a89d46012dbdad03fa9c9d3
@@ -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 info;
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 >= 1.9.
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
@@ -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 # rubocop:disable Performance/RedundantBlockCall
65
+ values = block.call(values) if block
66
66
  [r.begin, values]
67
67
  end.to_h
68
68
  end
@@ -230,26 +230,25 @@ module TimeMath
230
230
  end
231
231
  end
232
232
 
233
- # Creates an array of time unit starts between from and to. They will
234
- # have same granularity as from (e.g. if unit is day and from is
235
- # 2016-05-01 13:30, each of return values will be next day at 13:30),
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 [Array<Time or DateTime>]
239
- def to_a
240
- seq = []
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
- seq << iter
243
+ yield(op.call(iter))
245
244
 
246
245
  iter = unit.advance(iter)
247
246
  end
248
- seq << to unless exclude_end?
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
  #
@@ -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
- # info of origin would be preserved.
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 info
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 info
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 info
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 info
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 info
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 info
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
- protected
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 = to_components(tm).first(index + 1)
355
- new_from_components(tm, *components)
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 generate(tm, year: tm.year + 1, month: 1) if tm.month == 12
20
+ return Util.merge(tm, year: tm.year + 1, month: 1) if tm.month == 12
21
21
 
22
- t = generate(tm, month: tm.month + 1)
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 generate(tm, year: tm.year - 1, month: 12) if tm.month == 1
27
+ return Util.merge(tm, year: tm.year - 1, month: 12) if tm.month == 1
28
28
 
29
- t = generate(tm, month: tm.month - 1)
29
+ t = Util.merge(tm, month: tm.month - 1)
30
30
  fix_month(t, t.month - 1)
31
31
  end
32
32
 
@@ -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 == 0 ? 6 : tm.wday - 1
14
+ extra_days = tm.wday.zero? ? 6 : tm.wday - 1
15
15
  TimeMath.day.decrease(f, extra_days)
16
16
  end
17
17
 
@@ -7,7 +7,7 @@ module TimeMath
7
7
  end
8
8
 
9
9
  def measure(from, to)
10
- if generate(from, year: to.year) < to
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
- generate(tm, year: tm.year + steps.to_i)
20
+ Util.merge(tm, year: tm.year + steps.to_i)
21
21
  end
22
22
 
23
23
  def _decrease(tm, steps)
24
- generate(tm, year: tm.year - steps.to_i)
24
+ Util.merge(tm, year: tm.year - steps.to_i)
25
25
  end
26
26
  end
27
27
  end
@@ -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
@@ -1,4 +1,4 @@
1
1
  module TimeMath
2
2
  # @private
3
- VERSION = '0.0.5'.freeze
3
+ VERSION = '0.0.6'.freeze
4
4
  end
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.5
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-06-25 00:00:00.000000000 Z
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.4.8
161
+ rubygems_version: 2.5.2
162
162
  signing_key:
163
163
  specification_version: 4
164
164
  summary: Easy time math