Class: TimeRange

Inherits:
Range
  • Object
show all
Defined in:
lib/timerange.rb,
lib/timerange/version.rb

Constant Summary collapse

VERSION =
"0.0.4"

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(b = nil, e = Time.now, exclude_end = false, options = {}) ⇒ TimeRange

Returns a new instance of TimeRange.



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/timerange.rb', line 10

def initialize(b = nil, e = Time.now, exclude_end = false, options = {})
  if !b
    raise TypeError, "no implicit conversion of nil into Time"
  end

  if b.is_a?(Range)
    b, e, exclude_end = b.begin, b.end, b.exclude_end?
  end

  if b.is_a?(Hash)
    options, b, e, exclude_end = b, nil, nil, false
  elsif e.is_a?(Hash)
    options, e, exclude_end = e, Time.now, false
  end

  time_zone = options[:time_zone] || (b.respond_to?(:time_zone) && b.time_zone) || TimeRange.time_zone || Time.zone || "Etc/UTC"
  if time_zone.is_a?(ActiveSupport::TimeZone) or (time_zone = ActiveSupport::TimeZone[time_zone])
    # do nothing
  else
    raise "Unrecognized time zone"
  end

  b = time_zone.parse(b) if b.is_a?(String)
  e = time_zone.parse(e) if e.is_a?(String)
  b = b.in_time_zone(time_zone)
  e = e.in_time_zone(time_zone)

  if options[:duration]
    e = b + options[:duration]
    exclude_end = true
  end
  if options[:within]
    e = b + options[:within]
    b -= options[:within]
    exclude_end = false
  end

  @options = options.merge(time_zone: time_zone)

  super(b, e, exclude_end)
end

Class Attribute Details

.time_zoneObject

Returns the value of attribute time_zone.



7
8
9
# File 'lib/timerange.rb', line 7

def time_zone
  @time_zone
end

Class Method Details

.bucket(period, time, options = {}) ⇒ Object



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/timerange.rb', line 85

def self.bucket(period, time, options = {})
  time_zone = options[:time_zone] || TimeRange.time_zone || Time.zone || "Etc/UTC"
  day_start = options[:day_start] || 0
  week_start = options[:week_start] || 6

  week_start = [:mon, :tue, :wed, :thu, :fri, :sat, :sun].index((options[:week_start] || :sun).to_sym)
  if !week_start
    raise "Unrecognized :week_start option"
  end

  time = time.to_time.in_time_zone(time_zone) - day_start.hours

  time =
    case period.to_sym
    when :second
      time.change(usec: 0)
    when :minute
      time.change(sec: 0)
    when :hour
      time.change(min: 0)
    when :day
      time.beginning_of_day
    when :week
      # same logic as MySQL group
      weekday = (time.wday - 1) % 7
      (time - ((7 - week_start + weekday) % 7).days).midnight
    when :month
      time.beginning_of_month
    when :year
      time.beginning_of_year
    else
      raise "Invalid period"
    end

  time + day_start.hours
end

.today(options = {}) ⇒ Object



122
123
124
125
# File 'lib/timerange.rb', line 122

def self.today(options = {})
  date = Time.now
  new(date, date, options).expand(:day)
end

.yesterday(options = {}) ⇒ Object



127
128
129
130
# File 'lib/timerange.rb', line 127

def self.yesterday(options = {})
  date = Time.now - 1.day
  new(date, date, options).expand(:day)
end

Instance Method Details

#+(period) ⇒ Object



132
133
134
# File 'lib/timerange.rb', line 132

def +(period)
  self.class.new(self.begin + period, self.end + period, exclude_end?)
end

#-(period) ⇒ Object



136
137
138
# File 'lib/timerange.rb', line 136

def -(period)
  self.class.new(self.begin - period, self.end - period, exclude_end?)
end

#bucket(period, time, options = {}) ⇒ Object



81
82
83
# File 'lib/timerange.rb', line 81

def bucket(period, time, options = {})
  self.class.bucket(period, time, @options.merge(options))
end

#expand(period, options = {}) ⇒ Object



65
66
67
68
69
70
71
72
73
# File 'lib/timerange.rb', line 65

def expand(period, options = {})
  e =
    if exclude_end? and self.end == bucket(period, self.end, options)
      self.end
    else
      bucket(period, self.end + 1.send(period), options)
    end
  self.class.new(bucket(period, self.begin, options), e, true, @options.merge(options))
end

#expand_start(period, options = {}) ⇒ Object



75
76
77
78
79
# File 'lib/timerange.rb', line 75

def expand_start(period, options = {})
  e = self.end
  e = e.in_time_zone(options[:time_zone]) if options[:time_zone]
  self.class.new(bucket(period, self.begin, options), e, exclude_end?, @options.merge(options))
end

#step(period, options = {}) {|arr.last| ... } ⇒ Object

should step expand by default? TODO return enum

Yields:

  • (arr.last)


54
55
56
57
58
59
60
61
62
63
# File 'lib/timerange.rb', line 54

def step(period, options = {}, &block)
  period = period.is_a?(Symbol) || period.is_a?(String) ? 1.send(period) : period
  arr = [self.begin]
  yield(arr.last) if block_given?
  while v = arr.last + period and cover?(v)
    yield(v) if block_given?
    arr << v
  end
  arr
end