timerange 0.0.1 → 0.0.2

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