timeshifter 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +31 -0
- data/lib/timeshifter.rb +97 -0
- data/lib/timeshifter/version.rb +3 -0
- data/test/helper.rb +6 -0
- data/test/test_timeshifter.rb +71 -0
- metadata +73 -0
data/README.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
Timeshifter
|
2
|
+
===========
|
3
|
+
|
4
|
+
## DESCRIPTION
|
5
|
+
|
6
|
+
Timeshifter is a library for shifting time around within a day. You can set
|
7
|
+
valid hour ranges and Timeshifter will spread a time out within those ranges.
|
8
|
+
|
9
|
+
For example, say your valid ranges are outside business hours (midnight until
|
10
|
+
9am and 5pm until midnight). You can set those as your valid ranges and shift
|
11
|
+
your time within those ranges:
|
12
|
+
|
13
|
+
# Create a shifter for 12am-9am, 5pm-12am
|
14
|
+
shifter = Timeshifter.new([0..9, 17..24])
|
15
|
+
shifter.total_hours # => 16
|
16
|
+
shifter.shift(Time.utc(2010, 1, 1, 0, 0, 0)) # => "Fri Jan 01 00:00:00 UTC 2010"
|
17
|
+
shifter.shift(Time.utc(2010, 1, 1, 12, 0, 0)) # => "Fri Jan 01 08:00:00 UTC 2010"
|
18
|
+
shifter.shift(Time.utc(2010, 1, 1, 18, 0, 0)) # => "Fri Jan 01 20:00:00 UTC 2010"
|
19
|
+
shifter.shift(Time.utc(2010, 1, 1, 23, 59, 59)) # => "Fri Jan 01 23:59:59 UTC 2010"
|
20
|
+
|
21
|
+
Timeshifter follows the rules of [Semantic Versioning](http://semver.org/) and
|
22
|
+
uses [TomDoc](http://tomdoc.org/) for inline documentation.
|
23
|
+
|
24
|
+
|
25
|
+
## CONTRIBUTE
|
26
|
+
|
27
|
+
Have a great idea for Timeshifter? Awesome. Fork the repository and add a
|
28
|
+
feature or fix a bug. There are a couple things I ask:
|
29
|
+
|
30
|
+
1. You must have tests for all code you check in.
|
31
|
+
1. Create an appropriately named topic branch that contains your change.
|
data/lib/timeshifter.rb
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
lib = File.expand_path('../lib', File.dirname(__FILE__))
|
2
|
+
$:.unshift lib unless $:.include?(lib)
|
3
|
+
|
4
|
+
require 'timeshifter/version'
|
5
|
+
|
6
|
+
class Timeshifter
|
7
|
+
##############################################################################
|
8
|
+
#
|
9
|
+
# Constructor
|
10
|
+
#
|
11
|
+
##############################################################################
|
12
|
+
|
13
|
+
# Initializes an object that will shift time within a valid set of ranges.
|
14
|
+
#
|
15
|
+
# ranges - A list of ranges to shift time within.
|
16
|
+
def initialize(ranges)
|
17
|
+
raise "Ranges are required" if ranges.nil?
|
18
|
+
@ranges = ranges.compact.sort {|x,y| x.begin <=> y.begin}
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
##############################################################################
|
23
|
+
#
|
24
|
+
# Properties
|
25
|
+
#
|
26
|
+
##############################################################################
|
27
|
+
|
28
|
+
# The list of valid ranges.
|
29
|
+
def ranges
|
30
|
+
Array.new(@ranges)
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
##############################################################################
|
35
|
+
#
|
36
|
+
# Methods
|
37
|
+
#
|
38
|
+
##############################################################################
|
39
|
+
|
40
|
+
# Shifts the time to a valid time in the day based on the ranges provided.
|
41
|
+
#
|
42
|
+
# time - The time to shift.
|
43
|
+
#
|
44
|
+
# Returns a time that is within the valid ranges.
|
45
|
+
def shift(time)
|
46
|
+
return nil if time.nil?
|
47
|
+
|
48
|
+
# Check if it's UTC
|
49
|
+
is_utc = time.utc?
|
50
|
+
|
51
|
+
# Determine the total available seconds from the ranges.
|
52
|
+
tsec = (total_hours * 3600).to_f
|
53
|
+
raise "No hours available to shift within" if tsec == 0
|
54
|
+
|
55
|
+
# Determine original seconds in time for the day
|
56
|
+
osec = ((time.hour*3600) + (time.min*60) + time.sec).to_f
|
57
|
+
|
58
|
+
# Determine time shifted seconds in time for the day
|
59
|
+
sec = osec * (tsec/86400)
|
60
|
+
|
61
|
+
# Work through ranges and compact time
|
62
|
+
current = 0.0
|
63
|
+
ranges.each do |range|
|
64
|
+
rsec = ((range.end - range.begin) * 3600).to_f
|
65
|
+
|
66
|
+
# If time time is within this range calculate the position
|
67
|
+
if sec < current+rsec
|
68
|
+
shifted_time = Time.at(time.to_i - osec.to_i + (range.begin*3600)+(sec-current).to_i)
|
69
|
+
|
70
|
+
# Return UTC if that's what was passed in
|
71
|
+
if is_utc
|
72
|
+
shifted_time = shifted_time.getutc()
|
73
|
+
end
|
74
|
+
|
75
|
+
return shifted_time
|
76
|
+
end
|
77
|
+
|
78
|
+
# Add range second total to current seconds
|
79
|
+
current += rsec
|
80
|
+
end
|
81
|
+
|
82
|
+
# We should have been able to shift within a range by now
|
83
|
+
raise "Time could not be shifted inside range: #{osec} #{sec} #{current}"
|
84
|
+
end
|
85
|
+
|
86
|
+
# Calculates the total hours available based on the ranges provided.
|
87
|
+
def total_hours
|
88
|
+
total = 0
|
89
|
+
|
90
|
+
# Calculate total
|
91
|
+
ranges.each do |range|
|
92
|
+
total += range.end - range.begin
|
93
|
+
end
|
94
|
+
|
95
|
+
return total
|
96
|
+
end
|
97
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/helper'
|
2
|
+
|
3
|
+
class TimeshifterTestCase < MiniTest::Unit::TestCase
|
4
|
+
## Initialization ############################################################
|
5
|
+
|
6
|
+
def test_raise_error_for_nil_ranges
|
7
|
+
assert_raises RuntimeError do
|
8
|
+
shifter = Timeshifter.new(nil)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
## Total Hours ###############################################################
|
14
|
+
|
15
|
+
def test_should_calculate_total_hours_simple
|
16
|
+
shifter = Timeshifter.new([0..12])
|
17
|
+
assert_equal 12, shifter.total_hours
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_should_calculate_total_hours_complex
|
21
|
+
shifter = Timeshifter.new([0..8, 18..24])
|
22
|
+
assert_equal 14, shifter.total_hours
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_should_calculate_total_hours_for_empty_ranges
|
26
|
+
shifter = Timeshifter.new([])
|
27
|
+
assert_equal 0, shifter.total_hours
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
## Shifting ##################################################################
|
32
|
+
|
33
|
+
def test_should_shift_to_original_time
|
34
|
+
shifter = Timeshifter.new([0..24])
|
35
|
+
assert_equal 'Fri Jan 01 12:00:00 UTC 2010', shifter.shift(Time.utc(2010, 1, 1, 12, 0, 0)).to_s
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_should_shift_simple
|
39
|
+
shifter = Timeshifter.new([0..12])
|
40
|
+
assert_equal 'Fri Jan 01 04:00:00 UTC 2010', shifter.shift(Time.utc(2010, 1, 1, 8, 0, 0)).to_s
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_should_shift_complex
|
44
|
+
shifter = Timeshifter.new([0..8, 16..24])
|
45
|
+
assert_equal 'Fri Jan 01 06:00:00 UTC 2010', shifter.shift(Time.utc(2010, 1, 1, 9, 0, 0)).to_s
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_should_shift_to_secondary_range
|
49
|
+
shifter = Timeshifter.new([0..8, 16..24])
|
50
|
+
assert_equal 'Fri Jan 01 16:00:00 UTC 2010', shifter.shift(Time.utc(2010, 1, 1, 12, 0, 0)).to_s
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_should_shift_to_secondary_range2
|
54
|
+
shifter = Timeshifter.new([0..8, 16..24])
|
55
|
+
assert_equal 'Fri Jan 01 20:00:00 UTC 2010', shifter.shift(Time.utc(2010, 1, 1, 18, 0, 0)).to_s
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_should_shift_to_end_of_ranges
|
59
|
+
shifter = Timeshifter.new([0..8, 16..24])
|
60
|
+
assert_equal 'Fri Jan 01 23:59:59 UTC 2010', shifter.shift(Time.utc(2010, 1, 1, 23, 59, 59)).to_s
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
def test_should_shift_ranges_specified_in_readme
|
65
|
+
shifter = Timeshifter.new([0..9, 17..24])
|
66
|
+
assert_equal 'Fri Jan 01 00:00:00 UTC 2010', shifter.shift(Time.utc(2010, 1, 1, 0, 0, 0)).to_s
|
67
|
+
assert_equal 'Fri Jan 01 08:00:00 UTC 2010', shifter.shift(Time.utc(2010, 1, 1, 12, 0, 0)).to_s
|
68
|
+
assert_equal 'Fri Jan 01 20:00:00 UTC 2010', shifter.shift(Time.utc(2010, 1, 1, 18, 0, 0)).to_s
|
69
|
+
assert_equal 'Fri Jan 01 23:59:59 UTC 2010', shifter.shift(Time.utc(2010, 1, 1, 23, 59, 59)).to_s
|
70
|
+
end
|
71
|
+
end
|
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: timeshifter
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Ben Johnson
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-09-30 00:00:00 -06:00
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description:
|
23
|
+
email:
|
24
|
+
- benbjohnson@yahoo.com
|
25
|
+
executables: []
|
26
|
+
|
27
|
+
extensions: []
|
28
|
+
|
29
|
+
extra_rdoc_files: []
|
30
|
+
|
31
|
+
files:
|
32
|
+
- lib/timeshifter/version.rb
|
33
|
+
- lib/timeshifter.rb
|
34
|
+
- README.md
|
35
|
+
- test/helper.rb
|
36
|
+
- test/test_timeshifter.rb
|
37
|
+
has_rdoc: true
|
38
|
+
homepage:
|
39
|
+
licenses: []
|
40
|
+
|
41
|
+
post_install_message:
|
42
|
+
rdoc_options: []
|
43
|
+
|
44
|
+
require_paths:
|
45
|
+
- lib
|
46
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
47
|
+
none: false
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
hash: 3
|
52
|
+
segments:
|
53
|
+
- 0
|
54
|
+
version: "0"
|
55
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
hash: 3
|
61
|
+
segments:
|
62
|
+
- 0
|
63
|
+
version: "0"
|
64
|
+
requirements: []
|
65
|
+
|
66
|
+
rubyforge_project:
|
67
|
+
rubygems_version: 1.3.7
|
68
|
+
signing_key:
|
69
|
+
specification_version: 3
|
70
|
+
summary: A library for shifting time.
|
71
|
+
test_files:
|
72
|
+
- test/helper.rb
|
73
|
+
- test/test_timeshifter.rb
|