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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2c894dba974163b967591d9fdaf8b18cfb1dcc4d
4
- data.tar.gz: 1275ef9878ac3f4799dffafb8b9ed1f6504412fa
3
+ metadata.gz: 17b671b71b8905bfdd65ac8e0c3f620eb278f51f
4
+ data.tar.gz: 132d36c026b2da0f57cf3817228647eb74f210b9
5
5
  SHA512:
6
- metadata.gz: 5ebd11f24a6c1673512d102e73e10952176981654cb2915c0785c095420cbde8df9f63e6c75827a00e27f227a3e80340bdd4e5b22a6fcff15128165d2c52aa1e
7
- data.tar.gz: 3ae674ccabaf4bae6c58fdef2d331ffc77e6e4cc3017334b8816e29fbc79b1d8cd37ab6ee845255709d52dabe7026b38dcf7f13f11899d513b9a7a1851bbe008
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(range: 7.days.ago..Time.now)
17
- time_range.step(:day)
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.1"
6
+ VERSION = "0.0.2"
5
7
 
6
- def initialize(options = {})
7
- range = options[:range]
8
- super(range.begin, range.end, range.exclude_end?)
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
- def step(period, options = {})
12
- arr = [bucket(period, self.begin, options)]
13
- while v = arr.last + 1.send(period) and cover?(v)
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
- self.class.new(range: Range.new(bucket(period, self.begin, options), bucket(period, self.end + 1.send(period), options), true))
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 time_zone
24
- Time.zone
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
- day_start = 0
29
- week_start = 6 # sunday
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
- else # year
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(range: date..date).expand(:day)
115
+ new(date, date).expand(:day)
58
116
  end
59
117
 
60
118
  def self.yesterday
61
119
  date = Date.yesterday
62
- new(range: date..date).expand(:day)
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
@@ -2,3 +2,8 @@ require "bundler/setup"
2
2
  Bundler.require(:default)
3
3
  require "minitest/autorun"
4
4
  require "minitest/pride"
5
+ require "timecop"
6
+
7
+ Time.zone = "Pacific Time (US & Canada)"
8
+
9
+ Timecop.freeze
@@ -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(range: day..day).expand(:week).step(:day).size
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
@@ -23,4 +23,5 @@ Gem::Specification.new do |spec|
23
23
  spec.add_development_dependency "bundler", "~> 1.6"
24
24
  spec.add_development_dependency "rake"
25
25
  spec.add_development_dependency "minitest"
26
+ spec.add_development_dependency "timecop"
26
27
  end
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.1
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-21 00:00:00.000000000 Z
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