time_spanner 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|