time_spanner 1.0.0
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 +7 -0
- data/.gitignore +18 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +13 -0
- data/LICENSE.txt +22 -0
- data/README.md +60 -0
- data/Rakefile +11 -0
- data/lib/time_spanner.rb +8 -0
- data/lib/time_spanner/duration_chain.rb +55 -0
- data/lib/time_spanner/errors.rb +8 -0
- data/lib/time_spanner/time_span.rb +34 -0
- data/lib/time_spanner/time_unit_collector.rb +59 -0
- data/lib/time_spanner/time_units.rb +17 -0
- data/lib/time_spanner/time_units/base/calendar_unit.rb +30 -0
- data/lib/time_spanner/time_units/base/time_unit.rb +39 -0
- data/lib/time_spanner/time_units/base/unit.rb +31 -0
- data/lib/time_spanner/time_units/century.rb +30 -0
- data/lib/time_spanner/time_units/day.rb +25 -0
- data/lib/time_spanner/time_units/decade.rb +25 -0
- data/lib/time_spanner/time_units/hour.rb +15 -0
- data/lib/time_spanner/time_units/microsecond.rb +15 -0
- data/lib/time_spanner/time_units/millennium.rb +25 -0
- data/lib/time_spanner/time_units/millisecond.rb +15 -0
- data/lib/time_spanner/time_units/minute.rb +15 -0
- data/lib/time_spanner/time_units/month.rb +25 -0
- data/lib/time_spanner/time_units/nanosecond.rb +15 -0
- data/lib/time_spanner/time_units/second.rb +15 -0
- data/lib/time_spanner/time_units/week.rb +25 -0
- data/lib/time_spanner/time_units/year.rb +25 -0
- data/lib/time_spanner/version.rb +3 -0
- data/test/test_helper.rb +9 -0
- data/test/time_spanner/duration_chain_test.rb +267 -0
- data/test/time_spanner/time_spanner_test.rb +27 -0
- data/test/time_spanner/time_unit_collector_test.rb +66 -0
- data/test/time_spanner/time_units/base/calendar_unit_test.rb +17 -0
- data/test/time_spanner/time_units/base/time_unit_test.rb +18 -0
- data/test/time_spanner/time_units/base/unit_test.rb +37 -0
- data/test/time_spanner/time_units/century_test.rb +55 -0
- data/test/time_spanner/time_units/day_test.rb +84 -0
- data/test/time_spanner/time_units/decade_test.rb +67 -0
- data/test/time_spanner/time_units/hour_test.rb +56 -0
- data/test/time_spanner/time_units/microsecond_test.rb +56 -0
- data/test/time_spanner/time_units/millennium_test.rb +69 -0
- data/test/time_spanner/time_units/millisecond_test.rb +56 -0
- data/test/time_spanner/time_units/minute_test.rb +84 -0
- data/test/time_spanner/time_units/month_test.rb +68 -0
- data/test/time_spanner/time_units/nanosecond_test.rb +40 -0
- data/test/time_spanner/time_units/second_test.rb +56 -0
- data/test/time_spanner/time_units/week_test.rb +55 -0
- data/test/time_spanner/time_units/year_test.rb +91 -0
- data/time_spanner.gemspec +23 -0
- metadata +143 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6e2463079adde3dea23bf0f4ec07643d7f7b8287
|
4
|
+
data.tar.gz: 03b8c9c82c323a7c13a6da91e2fb08c6154ee798
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5714eae36ccaa238f3b2b4fcde65fb0032e4b1dcb3fb0cc7ff2683ad76fd6a9bd9a84ac189905642b37b8e0c442e11da34b11a5552f8bef9a912391691e8b53d
|
7
|
+
data.tar.gz: 691f5e479c64690ba0e102d72b6569e68dce4ecacd60430b55533dc313d67312414e7f1a2234f8657e3ed4af2428661c1145774b5a2c766f37a4caf57797019b
|
data/.gitignore
ADDED
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
time_spanner
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.0.0
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 TODO: Write your name
|
2
|
+
|
3
|
+
MIT License
|
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,60 @@
|
|
1
|
+
time_spanner
|
2
|
+
============
|
3
|
+
|
4
|
+
Returns a time span splitted in desired units given two timestamps.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
gem 'time_spanner'
|
11
|
+
|
12
|
+
And then execute:
|
13
|
+
|
14
|
+
$ bundle
|
15
|
+
|
16
|
+
Or install it yourself as:
|
17
|
+
|
18
|
+
$ gem install time_spanner
|
19
|
+
|
20
|
+
## Usage
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
TimeSpan.new Time.parse('2012-04-05 07:05:05'), Time.parse('3024-11-14 12:06:49')
|
24
|
+
```
|
25
|
+
returns:
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
{:millenniums=>1, :centuries=>0, :decades=>1, :years=>2, :months=>7, :weeks=>1, :days=>2, :hours=>6, :minutes=>1, :seconds=>44, :milliseconds=>0, :microseconds=>0, :nanoseconds=>0}
|
29
|
+
```
|
30
|
+
|
31
|
+
## Specifying units
|
32
|
+
|
33
|
+
Define which time units should be calculated.
|
34
|
+
Pass them within an Array as a third parameter.
|
35
|
+
|
36
|
+
Available units are:
|
37
|
+
<pre>:millenniums, :centuries, :decades, :years, :months, :weeks, :days, :hours, :minutes, :seconds, :milliseconds, :microseconds, :nanoseconds</pre>
|
38
|
+
|
39
|
+
If no units are supplied it defaults to all units.
|
40
|
+
|
41
|
+
|
42
|
+
### Example
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
TimeSpan.new Time.parse('2012-04-05 07:05:05'), Time.at(Time.parse(2012-04-05 07:10:12', 1243.345), [:seconds, :milliseconds, :microseconds, :nanoseconds])
|
46
|
+
```
|
47
|
+
returns:
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
{:seconds=>307, :milliseconds=>1, :microseconds=>243, :nanoseconds=>345}
|
51
|
+
```
|
52
|
+
|
53
|
+
|
54
|
+
## Contributing
|
55
|
+
|
56
|
+
1. Fork it
|
57
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
58
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
59
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
60
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/lib/time_spanner.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
module TimeSpanner
|
2
|
+
|
3
|
+
class DurationChain
|
4
|
+
extend Forwardable
|
5
|
+
include Enumerable
|
6
|
+
include TimeUnits
|
7
|
+
|
8
|
+
attr_accessor :remaining, :reverse, :units
|
9
|
+
attr_reader :to
|
10
|
+
alias :reverse? :reverse
|
11
|
+
|
12
|
+
def_delegator :units, :each
|
13
|
+
|
14
|
+
def initialize from, to, units
|
15
|
+
@from, @to = setup_times from, to
|
16
|
+
@remaining = to.to_r - from.to_r
|
17
|
+
@units = units.map &:new
|
18
|
+
|
19
|
+
calculate!
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
# Perform duration calculations for units in chain.
|
25
|
+
def calculate!
|
26
|
+
sort!
|
27
|
+
|
28
|
+
each do |unit|
|
29
|
+
calculate_unit unit
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def calculate_unit unit
|
34
|
+
unit.calculate remaining, to
|
35
|
+
unit.reverse! if reverse?
|
36
|
+
|
37
|
+
@remaining = unit.rest
|
38
|
+
end
|
39
|
+
|
40
|
+
# Units must be sorted to perform a correct calculation chain.
|
41
|
+
def sort!
|
42
|
+
@units = units.sort
|
43
|
+
end
|
44
|
+
|
45
|
+
def setup_times from, to
|
46
|
+
@reverse = to < from
|
47
|
+
new_from = reverse? ? to : from
|
48
|
+
new_to = reverse? ? from : to
|
49
|
+
|
50
|
+
[ new_from, new_to ]
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module TimeSpanner
|
2
|
+
|
3
|
+
class TimeSpan < Hash
|
4
|
+
include Errors
|
5
|
+
|
6
|
+
attr_reader :unit_chain
|
7
|
+
|
8
|
+
def initialize from, to, unit_names = []
|
9
|
+
validate! from, to
|
10
|
+
|
11
|
+
units = TimeUnitCollector.new( unit_names ).units
|
12
|
+
@unit_chain = DurationChain.new from.to_time, to.to_time, units
|
13
|
+
|
14
|
+
build!
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def build!
|
21
|
+
unit_chain.each do |unit|
|
22
|
+
self[ unit.plural_name ] = unit.amount
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def validate! from, to
|
27
|
+
unless [ from, to ].all? { |obj| obj.is_a?( Time ) || ( obj.respond_to?( :to_time ) && obj.to_time.is_a?( Time ) ) }
|
28
|
+
raise InvalidClassError, "Must convert to Time object!"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module TimeSpanner
|
2
|
+
|
3
|
+
class TimeUnitCollector
|
4
|
+
include TimeUnits
|
5
|
+
include Errors
|
6
|
+
|
7
|
+
AVAILABLE_UNITS = [ :millenniums, :centuries, :decades, :years, :months, :weeks, :days, :hours, :minutes, :seconds, :milliseconds, :microseconds, :nanoseconds ]
|
8
|
+
|
9
|
+
attr_reader :unit_names
|
10
|
+
attr_accessor :units
|
11
|
+
|
12
|
+
def initialize unit_names = []
|
13
|
+
@unit_names = collect_unit_names unit_names
|
14
|
+
@units = []
|
15
|
+
|
16
|
+
validate_unit_names!
|
17
|
+
collect!
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def collect!
|
24
|
+
unit_names.each do |name|
|
25
|
+
units << ( unit_by_name name )
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def unit_by_name name
|
30
|
+
case name
|
31
|
+
when :millenniums then Millennium
|
32
|
+
when :centuries then Century
|
33
|
+
when :decades then Decade
|
34
|
+
when :years then Year
|
35
|
+
when :months then Month
|
36
|
+
when :weeks then Week
|
37
|
+
when :days then Day
|
38
|
+
when :hours then Hour
|
39
|
+
when :minutes then Minute
|
40
|
+
when :seconds then Second
|
41
|
+
when :milliseconds then Millisecond
|
42
|
+
when :microseconds then Microsecond
|
43
|
+
when :nanoseconds then Nanosecond
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def collect_unit_names unit_names
|
48
|
+
!unit_names || unit_names.compact.empty? ? AVAILABLE_UNITS : unit_names
|
49
|
+
end
|
50
|
+
|
51
|
+
def validate_unit_names!
|
52
|
+
unit_names.each do |unit_name|
|
53
|
+
raise InvalidUnitError, "Unit '#{unit_name}' is not a valid time unit." unless AVAILABLE_UNITS.include? unit_name
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'time_spanner/time_units/base/unit'
|
2
|
+
require 'time_spanner/time_units/base/calendar_unit'
|
3
|
+
require 'time_spanner/time_units/base/time_unit'
|
4
|
+
|
5
|
+
require 'time_spanner/time_units/nanosecond'
|
6
|
+
require 'time_spanner/time_units/microsecond'
|
7
|
+
require 'time_spanner/time_units/millisecond'
|
8
|
+
require 'time_spanner/time_units/second'
|
9
|
+
require 'time_spanner/time_units/minute'
|
10
|
+
require 'time_spanner/time_units/hour'
|
11
|
+
require 'time_spanner/time_units/day'
|
12
|
+
require 'time_spanner/time_units/week'
|
13
|
+
require 'time_spanner/time_units/month'
|
14
|
+
require 'time_spanner/time_units/year'
|
15
|
+
require 'time_spanner/time_units/decade'
|
16
|
+
require 'time_spanner/time_units/century'
|
17
|
+
require 'time_spanner/time_units/millennium'
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module TimeSpanner
|
2
|
+
module TimeUnits
|
3
|
+
|
4
|
+
class CalendarUnit < Unit
|
5
|
+
|
6
|
+
attr_reader :from, :to
|
7
|
+
|
8
|
+
def initialize position
|
9
|
+
super position
|
10
|
+
end
|
11
|
+
|
12
|
+
def calculate duration, to
|
13
|
+
@to = to
|
14
|
+
@from = @to - duration.to_r
|
15
|
+
|
16
|
+
calculate_amount
|
17
|
+
calculate_rest at_amount( amount )
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def calculate_rest from
|
24
|
+
@rest = to.to_r - from.to_r
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module TimeSpanner
|
2
|
+
module TimeUnits
|
3
|
+
|
4
|
+
class TimeUnit < Unit
|
5
|
+
|
6
|
+
attr_reader :multiplier
|
7
|
+
|
8
|
+
def initialize position, multiplier
|
9
|
+
super position
|
10
|
+
|
11
|
+
@multiplier = multiplier
|
12
|
+
end
|
13
|
+
|
14
|
+
def calculate duration, to = nil
|
15
|
+
@duration = duration
|
16
|
+
|
17
|
+
calculate_amount
|
18
|
+
calculate_rest
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def calculate_amount
|
25
|
+
@amount = ( ( duration * multiplier ).round 13 ).to_i
|
26
|
+
end
|
27
|
+
|
28
|
+
def calculate_rest
|
29
|
+
@rest = duration - amount_in_seconds
|
30
|
+
end
|
31
|
+
|
32
|
+
def amount_in_seconds
|
33
|
+
amount.to_r / multiplier
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module TimeSpanner
|
2
|
+
module TimeUnits
|
3
|
+
|
4
|
+
class Unit
|
5
|
+
include Comparable
|
6
|
+
|
7
|
+
attr_reader :position
|
8
|
+
attr_accessor :duration, :amount, :rest
|
9
|
+
|
10
|
+
def initialize position
|
11
|
+
@position = position
|
12
|
+
@amount = 0
|
13
|
+
@rest = 0
|
14
|
+
end
|
15
|
+
|
16
|
+
def reverse!
|
17
|
+
@amount = -amount
|
18
|
+
end
|
19
|
+
|
20
|
+
def <=> other
|
21
|
+
position <=> other.position
|
22
|
+
end
|
23
|
+
|
24
|
+
def plural_name
|
25
|
+
"#{self.class.name.split('::').last.downcase}s".to_sym
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module TimeSpanner
|
2
|
+
module TimeUnits
|
3
|
+
|
4
|
+
class Century < CalendarUnit
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
super 2
|
8
|
+
end
|
9
|
+
|
10
|
+
# Override!
|
11
|
+
def plural_name
|
12
|
+
:centuries
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def calculate_amount
|
19
|
+
amount = ( to.year - from.year ) / 100
|
20
|
+
@amount = at_amount( amount ) > to ? amount - 1 : amount
|
21
|
+
end
|
22
|
+
|
23
|
+
def at_amount amount
|
24
|
+
( from.to_datetime >> amount * 1200 ).to_time
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|