timerange 0.0.1 → 0.0.2
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 +4 -4
- data/README.md +20 -3
- data/lib/timerange.rb +81 -15
- data/test/test_helper.rb +5 -0
- data/test/time_range_test.rb +37 -1
- data/timerange.gemspec +1 -0
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 17b671b71b8905bfdd65ac8e0c3f620eb278f51f
|
4
|
+
data.tar.gz: 132d36c026b2da0f57cf3817228647eb74f210b9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eb12938aa430be463edff9b7b763406c464677cf3309f2d6b32f0444c75ae04017903fa78275cec1992d99ca671d73ce0553141ffefdea7fae8447a528fc4ac5
|
7
|
+
data.tar.gz: fc04948e87a7d35967f8c0b2cd3aa24e546b5818b163903bfcc5ad6aad0578c327efaaf51b4605238e1eaebfd7fdb4bcd83a034e5bc1555895e00778f03d058d
|
data/README.md
CHANGED
@@ -13,9 +13,26 @@ gem 'timerange'
|
|
13
13
|
## Features
|
14
14
|
|
15
15
|
```ruby
|
16
|
-
time_range = TimeRange.new(
|
17
|
-
time_range.step(
|
18
|
-
time_range.expand(:week)
|
16
|
+
time_range = TimeRange.new(7.days.ago..Time.now)
|
17
|
+
time_range.step(1.day)
|
18
|
+
time_range.expand(:week).step(1.day)
|
19
|
+
|
20
|
+
TimeRange.new("2014-06-01", "2014-06-07")
|
21
|
+
TimeRange.new("2014-06-01", duration: 1.week)
|
22
|
+
TimeRange.new(4.weeks.ago).expand_start(:week) # last 4 weeks
|
23
|
+
|
24
|
+
TimeRange.today
|
25
|
+
TimeRange.yesterday
|
26
|
+
|
27
|
+
TimeRange.today + 4.weeks
|
28
|
+
TimeRange.today - 4.weeks
|
29
|
+
|
30
|
+
TimeRange.bucket(:hour, user.created_at)
|
31
|
+
TimeRange.bucket(:day, user.created_at, day_start: 2) # 2 am
|
32
|
+
TimeRange.bucket(:week, user.created_at, week_start: :mon) # start weeks on Monday
|
33
|
+
TimeRange.bucket(:month, user.created_at, time_zone: "Pacific Time (US & Canada)")
|
34
|
+
|
35
|
+
TimeRange.time_zone = "Pacific Time (US & Canada)" # defaults to Time.zone
|
19
36
|
```
|
20
37
|
|
21
38
|
## Contributing
|
data/lib/timerange.rb
CHANGED
@@ -1,34 +1,90 @@
|
|
1
|
+
require "time"
|
1
2
|
require "active_support/time"
|
3
|
+
require "active_support/core_ext/module/attribute_accessors"
|
2
4
|
|
3
5
|
class TimeRange < Range
|
4
|
-
VERSION = "0.0.
|
6
|
+
VERSION = "0.0.2"
|
5
7
|
|
6
|
-
|
7
|
-
|
8
|
-
|
8
|
+
mattr_accessor :time_zone
|
9
|
+
|
10
|
+
def initialize(b = nil, e = Time.now, exclude_end = false, options = {})
|
11
|
+
if b.is_a?(Range)
|
12
|
+
b, e, exclude_end = b.begin, b.end, b.exclude_end?
|
13
|
+
end
|
14
|
+
|
15
|
+
if b.is_a?(Hash)
|
16
|
+
options, b, e, exclude_end = b, nil, nil, false
|
17
|
+
elsif e.is_a?(Hash)
|
18
|
+
options, e, exclude_end = e, nil, false
|
19
|
+
end
|
20
|
+
|
21
|
+
time_zone = options[:time_zone] || self.class.time_zone || Time.zone || "Etc/UTC"
|
22
|
+
if time_zone.is_a?(ActiveSupport::TimeZone) or (time_zone = ActiveSupport::TimeZone[time_zone])
|
23
|
+
# do nothing
|
24
|
+
else
|
25
|
+
raise "Unrecognized time zone"
|
26
|
+
end
|
27
|
+
b = time_zone.parse(b) if b.is_a?(String)
|
28
|
+
e = time_zone.parse(e) if e.is_a?(String)
|
29
|
+
if options[:time_zone]
|
30
|
+
b = b.in_time_zone(b)
|
31
|
+
e = e.in_time_zone(e)
|
32
|
+
end
|
33
|
+
|
34
|
+
if options[:duration]
|
35
|
+
e = b + options[:duration]
|
36
|
+
exclude_end = true
|
37
|
+
end
|
38
|
+
|
39
|
+
super(b, e, exclude_end)
|
9
40
|
end
|
10
41
|
|
11
|
-
|
12
|
-
|
13
|
-
|
42
|
+
# should step expand by default?
|
43
|
+
# TODO return enum
|
44
|
+
def step(period, options = {}, &block)
|
45
|
+
period = period.is_a?(Symbol) || period.is_a?(String) ? 1.send(period) : period
|
46
|
+
arr = [self.begin]
|
47
|
+
yield(arr.last) if block_given?
|
48
|
+
while v = arr.last + period and cover?(v)
|
49
|
+
yield(v) if block_given?
|
14
50
|
arr << v
|
15
51
|
end
|
16
52
|
arr
|
17
53
|
end
|
18
54
|
|
19
55
|
def expand(period, options = {})
|
20
|
-
|
56
|
+
e =
|
57
|
+
if exclude_end? and self.end == bucket(period, self.end, options)
|
58
|
+
self.end
|
59
|
+
else
|
60
|
+
bucket(period, self.end + 1.send(period), options)
|
61
|
+
end
|
62
|
+
self.class.new(bucket(period, self.begin, options), e, true)
|
21
63
|
end
|
22
64
|
|
23
|
-
def
|
24
|
-
|
65
|
+
def expand_start(period, options = {})
|
66
|
+
e = self.end
|
67
|
+
e = e.in_time_zone(options[:time_zone]) if options[:time_zone]
|
68
|
+
self.class.new(bucket(period, self.begin, options), e, exclude_end?)
|
25
69
|
end
|
26
70
|
|
27
71
|
def bucket(period, time, options = {})
|
28
|
-
|
29
|
-
|
72
|
+
self.class.bucket(period, time, options)
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.bucket(period, time, options = {})
|
76
|
+
time_zone = options[:time_zone] || Time.zone
|
77
|
+
day_start = options[:day_start] || 0
|
78
|
+
week_start = options[:week_start] || 6
|
79
|
+
|
80
|
+
week_start = [:mon, :tue, :wed, :thu, :fri, :sat, :sun].index((options[:week_start] || :sun).to_sym)
|
81
|
+
if !week_start
|
82
|
+
raise "Unrecognized :week_start option"
|
83
|
+
end
|
84
|
+
|
30
85
|
time = time.to_time.in_time_zone(time_zone) - day_start.hours
|
31
86
|
|
87
|
+
period = period.to_sym
|
32
88
|
time =
|
33
89
|
case period
|
34
90
|
when :second
|
@@ -45,8 +101,10 @@ class TimeRange < Range
|
|
45
101
|
(time - ((7 - week_start + weekday) % 7).days).midnight
|
46
102
|
when :month
|
47
103
|
time.beginning_of_month
|
48
|
-
|
104
|
+
when :year
|
49
105
|
time.beginning_of_year
|
106
|
+
else
|
107
|
+
raise "Invalid period"
|
50
108
|
end
|
51
109
|
|
52
110
|
time + day_start.hours
|
@@ -54,12 +112,20 @@ class TimeRange < Range
|
|
54
112
|
|
55
113
|
def self.today
|
56
114
|
date = Date.today
|
57
|
-
new(
|
115
|
+
new(date, date).expand(:day)
|
58
116
|
end
|
59
117
|
|
60
118
|
def self.yesterday
|
61
119
|
date = Date.yesterday
|
62
|
-
new(
|
120
|
+
new(date, date).expand(:day)
|
121
|
+
end
|
122
|
+
|
123
|
+
def +(period)
|
124
|
+
self.class.new(self.begin + period, self.end + period, exclude_end?)
|
125
|
+
end
|
126
|
+
|
127
|
+
def -(period)
|
128
|
+
self.class.new(self.begin - period, self.end - period, exclude_end?)
|
63
129
|
end
|
64
130
|
|
65
131
|
end
|
data/test/test_helper.rb
CHANGED
data/test/time_range_test.rb
CHANGED
@@ -4,7 +4,43 @@ class TestTimeRange < Minitest::Test
|
|
4
4
|
|
5
5
|
def test_time_range
|
6
6
|
day = Time.parse("2014-06-01")
|
7
|
-
assert_equal 7, TimeRange.new(
|
7
|
+
assert_equal 7, TimeRange.new(day..day).expand(:week).step(:day).size
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_today
|
11
|
+
day = Time.now.midnight
|
12
|
+
tr = TimeRange.today
|
13
|
+
assert_equal day, tr.begin
|
14
|
+
assert_equal day + 1.day, tr.end
|
15
|
+
assert tr.exclude_end?
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_step_block
|
19
|
+
count = 0
|
20
|
+
TimeRange.today.expand(:week).step(:day) do |day|
|
21
|
+
count += 1
|
22
|
+
end
|
23
|
+
assert_equal 7, count
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_duration
|
27
|
+
tr = TimeRange.new("2014-06-01", duration: 1.week)
|
28
|
+
day = Time.zone.parse("2014-06-01")
|
29
|
+
assert_equal day, tr.begin
|
30
|
+
assert_equal day + 1.week, tr.end
|
31
|
+
assert tr.exclude_end?
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_last
|
35
|
+
tr = TimeRange.new(4.weeks.ago)
|
36
|
+
assert_equal 4.weeks.ago, tr.begin
|
37
|
+
assert_equal Time.zone.now, tr.end
|
38
|
+
assert !tr.exclude_end?
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_math
|
42
|
+
assert_equal TimeRange.today, TimeRange.yesterday + 1.day
|
43
|
+
assert_equal TimeRange.yesterday, TimeRange.today - 1.day
|
8
44
|
end
|
9
45
|
|
10
46
|
end
|
data/timerange.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: timerange
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kane
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-06-
|
11
|
+
date: 2014-06-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: timecop
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
69
83
|
description: Time ranges for Ruby
|
70
84
|
email:
|
71
85
|
- andrew@chartkick.com
|