time_calc 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +149 -0
- data/lib/time_calc.rb +273 -0
- data/lib/time_calc/diff.rb +291 -0
- data/lib/time_calc/dst.rb +54 -0
- data/lib/time_calc/op.rb +70 -0
- data/lib/time_calc/sequence.rb +130 -0
- data/lib/time_calc/types.rb +58 -0
- data/lib/time_calc/units.rb +57 -0
- data/lib/time_calc/value.rb +223 -0
- data/lib/time_calc/version.rb +6 -0
- metadata +211 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: '079469c094dfa9462e10854c885d962aeb8f047c'
|
4
|
+
data.tar.gz: c7f5d1d7d6f665b490ec48bb2d85a4830a030761
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ba7158a430d4968675210fe5e981d203178d59aca4c2aadfd0de26fa856fff23740aa4b6280b9ce67d6e507f5c78ca8a1ee519cd0d74ffb5a6678fecd66209fd
|
7
|
+
data.tar.gz: c874789108c36d802ea023a7ea6dbb0956d4f835a05ca2318232f0cbddee5b3f942ded7f37d1373eec191ad7ab6b09aaca5df1a354db204e83b7a6a22d345bd7
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2019 Victor 'Zverok' Shepelev
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
# TimeCalc -- next generation of Time arithmetic library
|
2
|
+
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/time_calc.svg)](http://badge.fury.io/rb/time_calc)
|
4
|
+
[![Build Status](https://travis-ci.org/zverok/time_calc.svg?branch=master)](https://travis-ci.org/zverok/time_calc)
|
5
|
+
[![Documentation](http://b.repl.ca/v1/yard-docs-blue.png)](http://rubydoc.info/gems/time_calc/frames)
|
6
|
+
|
7
|
+
**TimeCalc** tries to provide a way to do **simple time arithmetic** in a modern, readable, idiomatic, no-"magic" Ruby.
|
8
|
+
|
9
|
+
_**NB:** TimeCalc is a continuation of [TimeMath](https://github.com/zverok/time_math2) project. As I decided to change API significantly (completely, in fact) and drop a lot of "nice to have but nobody uses" features, it is a new project rather than "absolutely incompatible new version". See [API design](#api-design) section to understand how and why TimeCalc is different._
|
10
|
+
|
11
|
+
## Features
|
12
|
+
|
13
|
+
* Small, clean, pure-Ruby, idiomatic, no monkey-patching, no dependencies (except `backports`);
|
14
|
+
* Arithmetic akin to what Ruby numbers provide: `+`/`-`, `floor`/`ceil`/`round`, enumerable sequences (`step`/`to`);
|
15
|
+
* Works with `Time`, `Date` and `DateTime` and allows to mix them freely (e.g. create sequences from `Date` to `Time`, calculate their diffs);
|
16
|
+
* Tries its best to preserve timezone/offset information:
|
17
|
+
* **on Ruby 2.6+**, for `Time` with real timezones, preserves them;
|
18
|
+
* on Ruby < 2.6, preserves at least `utc_offset` of `Time`;
|
19
|
+
* for `DateTime` preserves zone name.
|
20
|
+
|
21
|
+
## Synopsis
|
22
|
+
|
23
|
+
### Arithmetic with units
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
require 'time_calc'
|
27
|
+
|
28
|
+
TC = TimeCalc
|
29
|
+
|
30
|
+
t = Time.parse('2019-03-14 08:06:15')
|
31
|
+
|
32
|
+
TC.(t).+(3, :hours)
|
33
|
+
# => 2019-03-14 11:06:15 +0200
|
34
|
+
TC.(t).round(:week)
|
35
|
+
# => 2019-03-11 00:00:00 +0200
|
36
|
+
|
37
|
+
# TimeCalc.call(Time.now) shortcut:
|
38
|
+
TC.now.floor(:day)
|
39
|
+
# => beginning of the today
|
40
|
+
```
|
41
|
+
|
42
|
+
Operations supported:
|
43
|
+
|
44
|
+
* `+`, `-`
|
45
|
+
* `ceil`, `round`, `floor`
|
46
|
+
|
47
|
+
Units supported:
|
48
|
+
|
49
|
+
* `:sec` (also `:second`, `:seconds`);
|
50
|
+
* `:min` (`:minute`, `:minutes`);
|
51
|
+
* `:hour`/`:hours`;
|
52
|
+
* `:day`/`:days`;
|
53
|
+
* `:week`/`:weeks`;
|
54
|
+
* `:month`/`:months`;
|
55
|
+
* `:year`/`:years`.
|
56
|
+
|
57
|
+
Timezone preservation on Ruby 2.6:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
require 'tzinfo'
|
61
|
+
t = Time.new(2019, 9, 1, 14, 30, 12, TZInfo::Timezone.get('Europe/Kiev'))
|
62
|
+
# => 2019-09-01 14:30:12 +0300
|
63
|
+
# ^^^^^
|
64
|
+
TimeCalc.(t).+(3, :months) # jump over DST: we have +3 in summer and +2 in winter
|
65
|
+
# => 2019-12-01 14:30:12 +0200
|
66
|
+
# ^^^^^
|
67
|
+
```
|
68
|
+
<small>(Random fun fact: it is Kyiv, not Kiev!)</small>
|
69
|
+
|
70
|
+
### Difference of two values
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
diff = TC.(t) - Time.parse('2019-02-30 16:30')
|
74
|
+
# => #<TimeCalc::Diff(2019-03-14 08:06:15 +0200 − 2019-03-02 16:30:00 +0200)>
|
75
|
+
diff.days # or any other supported unit
|
76
|
+
# => 11
|
77
|
+
diff.factorize
|
78
|
+
# => {:year=>0, :month=>0, :week=>1, :day=>4, :hour=>15, :min=>36, :sec=>15}
|
79
|
+
```
|
80
|
+
|
81
|
+
There are several options to [Diff#factorize](https://www.rubydoc.info/gems/time_calc/TimeCalc/Diff#factorize-instance_method) to obtain the most useful result.
|
82
|
+
|
83
|
+
### Chains of operations
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
TC.wrap(t).+(1, :hour).round(:min).unwrap
|
87
|
+
# => 2019-03-14 09:06:00 +0200
|
88
|
+
|
89
|
+
# proc constructor synopsys:
|
90
|
+
times = ['2019-06-01 14:30', '2019-06-05 17:10', '2019-07-02 13:40'].map { |t| Time.parse(t) }
|
91
|
+
times.map(&TC.+(1, :hour).round(:min))
|
92
|
+
# => [2019-06-01 15:30:00 +0300, 2019-06-05 18:10:00 +0300, 2019-07-02 14:40:00 +0300]
|
93
|
+
```
|
94
|
+
|
95
|
+
### Enumerable time sequences
|
96
|
+
|
97
|
+
```ruby
|
98
|
+
TC.(t).step(2, :weeks)
|
99
|
+
# => #<TimeCalc::Sequence (2019-03-14 08:06:15 +0200 - ...):step(2 weeks)>
|
100
|
+
TC.(t).step(2, :weeks).first(3)
|
101
|
+
# => [2019-03-14 08:06:15 +0200, 2019-03-28 08:06:15 +0200, 2019-04-11 09:06:15 +0300]
|
102
|
+
TC.(t).to(Time.parse('2019-04-30 16:30')).step(3, :weeks).to_a
|
103
|
+
# => [2019-03-14 08:06:15 +0200, 2019-04-04 09:06:15 +0300, 2019-04-25 09:06:15 +0300]
|
104
|
+
TC.(t).for(3, :months).step(4, :weeks).to_a
|
105
|
+
# => [2019-03-14 08:06:15 +0200, 2019-04-11 09:06:15 +0300, 2019-05-09 09:06:15 +0300, 2019-06-06 09:06:15 +0300]
|
106
|
+
```
|
107
|
+
|
108
|
+
## API design
|
109
|
+
|
110
|
+
The idea of this library (as well as the idea of the previous one) grew of the simple question "how do you say `<some time> + 1 hour` in good Ruby?" This question also leads (me) to notifying that other arithmetical operations (like rounding, or `<value> up to <value> with step <value>`) seem to be applicable to `Time` or `Date` values as well.
|
111
|
+
|
112
|
+
Prominent ActiveSupport's answer of extending simple numbers to respond to `1.year` never felt totally right to me. I am not completely against-any-monkey-patches kind of guy, it just doesn't sit right, to say "number has a method to produce duration". One of the attempts to find an alternative has led me to the creation of [time_math2](https://github.com/zverok/time_math2), which gained some (modest) popularity by presenting things this way: `TimeMath.year.advance(time, 1)`.
|
113
|
+
|
114
|
+
TBH, using the library myself only eventually, I have never been too happy with it: it never felt really natural, so I constantly forgot "what should I do to calculate '2 days ago'". This simplest use case (some time from now) in `TimeMath` looked too far from "how you pronounce it":
|
115
|
+
|
116
|
+
```ruby
|
117
|
+
# Natural language: 2 days ago
|
118
|
+
# "Formalized": now - 2 days
|
119
|
+
|
120
|
+
# ActiveSupport:
|
121
|
+
Time.now + 2.days
|
122
|
+
# also there is 2.days.ago, but I am not a big fan of "1000 synonyms just for naturality"
|
123
|
+
|
124
|
+
# TimeMath:
|
125
|
+
TimMath.day.decrease(Time.now, 2) # Ughhh what? "Day decrease now 2"?
|
126
|
+
```
|
127
|
+
|
128
|
+
The thought process that led to the new library is:
|
129
|
+
|
130
|
+
* `(2, days)` is just a _tuple_ of two unrelated data elements
|
131
|
+
* `days` is "internal name that makes sense inside the code", which we represent by `Symbol` in Ruby
|
132
|
+
* Math operators can be called just like regular methods: `.+(something)`, which may look unusual at first, but can be super-handy even with simple numbers, in method chaining -- I am grateful to my Verbit's colleague Roman Yarovoy to pointing at that fact (or rather its usefulness);
|
133
|
+
* To chain some calculations with Ruby core type without extending this type, we can just "wrap" it into a monad-like object, do the calculations, and unwrap at the end (TimeMath itself, and my Hash-processing gem [hm](https://github.com/zverok/hm) have used this approach).
|
134
|
+
|
135
|
+
So, here we go:
|
136
|
+
```ruby
|
137
|
+
TimeCalc.(Time.now).-(2, :days)
|
138
|
+
# Small shortcut, as `Time.now` is the frequent start value for such calculations:
|
139
|
+
TimeCalc.now.-(2, :days)
|
140
|
+
```
|
141
|
+
|
142
|
+
The rest of the design (see examples above) just followed naturally. There could be different opinions on the approach, but for myself the resulting API looks straightforward, hard to forget and very regular (in fact, all the hard time calculations, including support for different types, zones, DST and stuff, are done in two core methods, and the rest was easy to define in terms of those methods, which is a sign of consistency).
|
143
|
+
|
144
|
+
¯\\\_(ツ)_/¯
|
145
|
+
|
146
|
+
## Author & license
|
147
|
+
|
148
|
+
* [Victor Shepelev](https://zverok.github.io)
|
149
|
+
* [MIT](https://github.com/zverok/time_calc/blob/master/LICENSE.txt).
|
data/lib/time_calc.rb
ADDED
@@ -0,0 +1,273 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'date'
|
4
|
+
require 'time'
|
5
|
+
|
6
|
+
require_relative 'time_calc/units'
|
7
|
+
require_relative 'time_calc/types'
|
8
|
+
require_relative 'time_calc/dst'
|
9
|
+
require_relative 'time_calc/value'
|
10
|
+
|
11
|
+
# Module for time arithmetic.
|
12
|
+
#
|
13
|
+
# Examples of usage:
|
14
|
+
#
|
15
|
+
# ```ruby
|
16
|
+
# TimeCalc.(Time.now).+(1, :day)
|
17
|
+
# # => 2019-07-04 23:28:54 +0300
|
18
|
+
# TimeCalc.(Time.now).round(:hour)
|
19
|
+
# # => 2019-07-03 23:00:00 +0300
|
20
|
+
#
|
21
|
+
# # Operations with Time.now and Date.today also have their shortcuts:
|
22
|
+
# TimeCalc.now.-(3, :days)
|
23
|
+
# # => 2019-06-30 23:28:54 +0300
|
24
|
+
# TimeCalc.today.ceil(:month)
|
25
|
+
# # => #<Date: 2019-08-01 ((2458697j,0s,0n),+0s,2299161j)>
|
26
|
+
#
|
27
|
+
# # If you need to perform several operations TimeCalc.from wraps your value:
|
28
|
+
# TimeCalc.from(Time.parse('2019-06-14 13:40')).+(10, :days).floor(:week).unwrap
|
29
|
+
# # => 2019-06-24 00:00:00 +0300
|
30
|
+
#
|
31
|
+
# # TimeCalc#- also can be used to calculate difference between time values
|
32
|
+
# diff = TimeCalc.(Time.parse('2019-07-03 23:32')) - Time.parse('2019-06-14 13:40')
|
33
|
+
# # => #<TimeCalc::Diff(2019-07-03 23:32:00 +0300 − 2019-06-14 13:40:00 +0300)>
|
34
|
+
# diff.days # => 19
|
35
|
+
# diff.hours # => 465
|
36
|
+
# diff.factorize
|
37
|
+
# # => {:year=>0, :month=>0, :week=>2, :day=>5, :hour=>9, :min=>52, :sec=>0}
|
38
|
+
# diff.factorize(max: :day)
|
39
|
+
# # => {:day=>19, :hour=>9, :min=>52, :sec=>0}
|
40
|
+
#
|
41
|
+
# # Enumerable sequences of time values
|
42
|
+
# sequence = TimeCalc.(Time.parse('2019-06-14 13:40'))
|
43
|
+
# .to(Time.parse('2019-07-03 23:32'))
|
44
|
+
# .step(5, :hours)
|
45
|
+
# # => #<TimeCalc::Sequence (2019-06-14 13:40:00 +0300 - 2019-07-03 23:32:00 +0300):step(5 hours)>
|
46
|
+
# sequence.to_a
|
47
|
+
# # => [2019-06-14 13:40:00 +0300, 2019-06-14 18:40:00 +0300, 2019-06-14 23:40:00 +0300, ...
|
48
|
+
# sequence.first(2)
|
49
|
+
# # => [2019-06-14 13:40:00 +0300, 2019-06-14 18:40:00 +0300]
|
50
|
+
#
|
51
|
+
# # Construct operations to apply as a proc:
|
52
|
+
# times = ['2019-06-01 14:30', '2019-06-05 17:10', '2019-07-02 13:40'].map { |t| Time.parse(t) }
|
53
|
+
# # => [2019-06-01 14:30:00 +0300, 2019-06-05 17:10:00 +0300, 2019-07-02 13:40:00 +0300]
|
54
|
+
# times.map(&TimeCalc.+(1, :week).round(:day))
|
55
|
+
# # => [2019-06-09 00:00:00 +0300, 2019-06-13 00:00:00 +0300, 2019-07-10 00:00:00 +0300]
|
56
|
+
# ```
|
57
|
+
#
|
58
|
+
# See method docs below for details and supported arguments.
|
59
|
+
#
|
60
|
+
class TimeCalc
|
61
|
+
class << self
|
62
|
+
alias call new
|
63
|
+
|
64
|
+
# Shortcut for `TimeCalc.(Time.now)`
|
65
|
+
# @return [TimeCalc]
|
66
|
+
def now
|
67
|
+
new(Time.now)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Shortcut for `TimeCalc.(Date.today)`
|
71
|
+
# @return [TimeCalc]
|
72
|
+
def today
|
73
|
+
new(Date.today)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Returns {Value} wrapper, useful for performing several operations at once:
|
77
|
+
#
|
78
|
+
# ```ruby
|
79
|
+
# TimeCalc.from(Time.parse('2019-06-14 13:40')).+(10, :days).floor(:week).unwrap
|
80
|
+
# # => 2019-06-24 00:00:00 +0300
|
81
|
+
# ```
|
82
|
+
#
|
83
|
+
# @param date_or_time [Time, Date, DateTime]
|
84
|
+
# @return [Value]
|
85
|
+
def from(date_or_time)
|
86
|
+
Value.new(date_or_time)
|
87
|
+
end
|
88
|
+
|
89
|
+
# Shortcut for `TimeCalc.from(Time.now)`
|
90
|
+
# @return [Value]
|
91
|
+
def from_now
|
92
|
+
from(Time.now)
|
93
|
+
end
|
94
|
+
|
95
|
+
# Shortcut for `TimeCalc.from(Date.today)`
|
96
|
+
# @return [Value]
|
97
|
+
def from_today
|
98
|
+
from(Date.today)
|
99
|
+
end
|
100
|
+
|
101
|
+
alias wrap from
|
102
|
+
alias wrap_now from_now
|
103
|
+
alias wrap_today from_today
|
104
|
+
end
|
105
|
+
|
106
|
+
# @private
|
107
|
+
attr_reader :value
|
108
|
+
|
109
|
+
# Creates a "temporary" wrapper, which would be unwrapped after first operation:
|
110
|
+
#
|
111
|
+
# ```ruby
|
112
|
+
# TimeCalc.new(Time.now).round(:hour)
|
113
|
+
# # => 2019-07-03 23:00:00 +0300
|
114
|
+
# ```
|
115
|
+
#
|
116
|
+
# The constructor also aliased as `.call` which allows for nicer (for some eyes) code:
|
117
|
+
#
|
118
|
+
# ```ruby
|
119
|
+
# TimeCalc.(Time.now).round(:hour)
|
120
|
+
# # => 2019-07-03 23:00:00 +0300
|
121
|
+
# ```
|
122
|
+
#
|
123
|
+
# See {.from} if you need to perform several math operations on same value.
|
124
|
+
#
|
125
|
+
# @param date_or_time [Time, Date, DateTime]
|
126
|
+
def initialize(date_or_time)
|
127
|
+
@value = Value.new(date_or_time)
|
128
|
+
end
|
129
|
+
|
130
|
+
# @private
|
131
|
+
def inspect
|
132
|
+
'#<%s(%s)>' % [self.class, @value.unwrap]
|
133
|
+
end
|
134
|
+
|
135
|
+
# @return [true,false]
|
136
|
+
def ==(other)
|
137
|
+
other.is_a?(self.class) && other.value == value
|
138
|
+
end
|
139
|
+
|
140
|
+
# @!method merge(**attrs)
|
141
|
+
# Replaces specified components of date/time, preserves the rest.
|
142
|
+
#
|
143
|
+
# @example
|
144
|
+
# TimeCalc.(Date.parse('2018-06-01')).merge(year: 1983)
|
145
|
+
# # => #<Date: 1983-06-01>
|
146
|
+
#
|
147
|
+
# @param attrs [Hash<Symbol => Integer>]
|
148
|
+
# @return [Time, Date, DateTime] value of the same type that was initial wrapped value.
|
149
|
+
|
150
|
+
# @!method floor(unit)
|
151
|
+
# Floors (rounds down) date/time to nearest `unit`.
|
152
|
+
#
|
153
|
+
# @example
|
154
|
+
# TimeCalc.(Time.parse('2018-06-23 12:30')).floor(:month)
|
155
|
+
# # => 2018-06-01 00:00:00 +0300
|
156
|
+
#
|
157
|
+
# @param unit [Symbol]
|
158
|
+
# @return [Time, Date, DateTime] value of the same type that was initial wrapped value.
|
159
|
+
|
160
|
+
# @!method ceil(unit)
|
161
|
+
# Ceils (rounds up) date/time to nearest `unit`.
|
162
|
+
#
|
163
|
+
# @example
|
164
|
+
# TimeCalc.(Time.parse('2018-06-23 12:30')).ceil(:month)
|
165
|
+
# # => 2018-07-01 00:00:00 +0300
|
166
|
+
#
|
167
|
+
# @param unit [Symbol]
|
168
|
+
# @return [Time, Date, DateTime] value of the same type that was initial wrapped value.
|
169
|
+
|
170
|
+
# @!method round(unit)
|
171
|
+
# Rounds (up or down) date/time to nearest `unit`.
|
172
|
+
#
|
173
|
+
# @example
|
174
|
+
# TimeCalc.(Time.parse('2018-06-23 12:30')).round(:month)
|
175
|
+
# # => 2018-07-01 00:00:00 +0300
|
176
|
+
#
|
177
|
+
# @param unit [Symbol]
|
178
|
+
# @return [Time, Date, DateTime] value of the same type that was initial wrapped value.
|
179
|
+
|
180
|
+
# @!method +(span, unit)
|
181
|
+
# Add `<span units>` to wrapped value
|
182
|
+
# @example
|
183
|
+
# TimeCalc.(Time.parse('2019-07-03 23:28:54')).+(1, :day)
|
184
|
+
# # => 2019-07-04 23:28:54 +0300
|
185
|
+
# @param span [Integer]
|
186
|
+
# @param unit [Symbol]
|
187
|
+
# @return [Date, Time, DateTime] value of the same type that was initial wrapped value.
|
188
|
+
|
189
|
+
# @!method -(span_or_other, unit=nil)
|
190
|
+
# @overload -(span, unit)
|
191
|
+
# Subtracts `span units` from wrapped value.
|
192
|
+
# @param span [Integer]
|
193
|
+
# @param unit [Symbol]
|
194
|
+
# @return [Date, Time, DateTime] value of the same type that was initial wrapped value.
|
195
|
+
# @overload -(date_or_time)
|
196
|
+
# Produces {Diff}, allowing to calculate structured difference between two points in time.
|
197
|
+
# @example
|
198
|
+
# t1 = Time.parse('2019-06-01 14:50')
|
199
|
+
# t2 = Time.parse('2019-06-15 12:10')
|
200
|
+
# (TimeCalc.(t2) - t1).days
|
201
|
+
# # => 13
|
202
|
+
# @param date_or_time [Date, Time, DateTime]
|
203
|
+
# @return [Diff]
|
204
|
+
# @return [Time or Diff]
|
205
|
+
|
206
|
+
# @!method to(date_or_time)
|
207
|
+
# Produces {Sequence} from this value to `date_or_time`
|
208
|
+
#
|
209
|
+
# @param date_or_time [Date, Time, DateTime]
|
210
|
+
# @return [Sequence]
|
211
|
+
|
212
|
+
# @!method step(span, unit = nil)
|
213
|
+
# Produces endless {Sequence} from this value, with step specified.
|
214
|
+
#
|
215
|
+
# @overload step(unit)
|
216
|
+
# Shortcut for `step(1, unit)`
|
217
|
+
# @param unit [Symbol]
|
218
|
+
# @overload step(span, unit)
|
219
|
+
# @example
|
220
|
+
# TimeCalc.(Time.parse('2019-06-01 14:50')).step(1, :day).take(3)
|
221
|
+
# # => [2019-06-01 14:50:00 +0300, 2019-06-02 14:50:00 +0300, 2019-06-03 14:50:00 +0300]
|
222
|
+
# @param span [Integer]
|
223
|
+
# @param unit [Symbol]
|
224
|
+
# @return [Sequence]
|
225
|
+
|
226
|
+
# @!method for(span, unit)
|
227
|
+
# Produces {Sequence} from this value to `this + <span units>`
|
228
|
+
#
|
229
|
+
# @example
|
230
|
+
# TimeCalc.(Time.parse('2019-06-01 14:50')).for(2, :weeks).step(1, :day).count
|
231
|
+
# # => 15
|
232
|
+
# @param span [Integer]
|
233
|
+
# @param unit [Symbol]
|
234
|
+
# @return [Sequence]
|
235
|
+
|
236
|
+
# @private
|
237
|
+
MATH_OPERATIONS = %i[merge truncate floor ceil round + -].freeze
|
238
|
+
# @private
|
239
|
+
OPERATIONS = MATH_OPERATIONS.+(%i[to step for]).freeze
|
240
|
+
|
241
|
+
OPERATIONS.each do |name|
|
242
|
+
define_method(name) { |*args|
|
243
|
+
@value.public_send(name, *args).then { |res| res.is_a?(Value) ? res.unwrap : res }
|
244
|
+
}
|
245
|
+
end
|
246
|
+
|
247
|
+
class << self
|
248
|
+
MATH_OPERATIONS.each do |name|
|
249
|
+
define_method(name) { |*args| Op.new([[name, *args]]) }
|
250
|
+
end
|
251
|
+
|
252
|
+
# @!parse
|
253
|
+
# # Creates operation to perform {#+}`(span, unit)`
|
254
|
+
# # @return [Op]
|
255
|
+
# def TimeCalc.+(span, unit); end
|
256
|
+
# # Creates operation to perform {#-}`(span, unit)`
|
257
|
+
# # @return [Op]
|
258
|
+
# def TimeCalc.-(span, unit); end
|
259
|
+
# # Creates operation to perform {#floor}`(unit)`
|
260
|
+
# # @return [Op]
|
261
|
+
# def TimeCalc.floor(unit); end
|
262
|
+
# # Creates operation to perform {#ceil}`(unit)`
|
263
|
+
# # @return [Op]
|
264
|
+
# def TimeCalc.ceil(unit); end
|
265
|
+
# # Creates operation to perform {#round}`(unit)`
|
266
|
+
# # @return [Op]
|
267
|
+
# def TimeCalc.round(unit); end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
require_relative 'time_calc/op'
|
272
|
+
require_relative 'time_calc/sequence'
|
273
|
+
require_relative 'time_calc/diff'
|