Module: Daru::DateTimeIndexHelper

Defined in:
lib/daru/date_time/index.rb

Overview

Private module for storing helper functions for DateTimeIndex.

Constant Summary collapse

OFFSETS_HASH =
{
  'S'  => Daru::Offsets::Second,
  'M'  => Daru::Offsets::Minute,
  'H'  => Daru::Offsets::Hour,
  'D'  => Daru::Offsets::Day,
  'W'  => Daru::Offsets::Week,
  'MONTH' => Daru::Offsets::Month,
  'MB' => Daru::Offsets::MonthBegin,
  'ME' => Daru::Offsets::MonthEnd,
  'YEAR' => Daru::Offsets::Year,
  'YB' => Daru::Offsets::YearBegin,
  'YE' => Daru::Offsets::YearEnd
}.freeze
TIME_INTERVALS =
{
  Rational(1,1)     => Daru::Offsets::Day,
  Rational(1,24)    => Daru::Offsets::Hour,
  Rational(1,1440)  => Daru::Offsets::Minute,
  Rational(1,86_400) => Daru::Offsets::Second
}.freeze

Class Method Summary collapse

Class Method Details

.begin_from_offset?(offset, start) ⇒ Boolean

Returns:

  • (Boolean)


69
70
71
72
73
74
75
76
# File 'lib/daru/date_time/index.rb', line 69

def begin_from_offset? offset, start
  if offset.is_a?(Daru::Offsets::Tick) ||
     (offset.respond_to?(:on_offset?) && offset.on_offset?(start))
    true
  else
    false
  end
end

.date_time_from(date_string, date_precision) ⇒ Object



135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/daru/date_time/index.rb', line 135

def date_time_from date_string, date_precision
  case date_precision
  when :year
    DateTime.new(date_string.gsub(/[^0-9]/, '').to_i)
  when :month
    DateTime.new(
      date_string.match(/\d\d\d\d/).to_s.to_i,
      date_string.match(/\-\d?\d/).to_s.delete('-').to_i
    )
  else
    DateTime.parse date_string
  end
end

.determine_date_precision_of(date_string) ⇒ Object



149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/daru/date_time/index.rb', line 149

def determine_date_precision_of date_string
  case date_string
  when /\d\d\d\d\-\d?\d\-\d?\d \d?\d:\d?\d:\d?\d/
    :sec
  when /\d\d\d\d\-\d?\d\-\d?\d \d?\d:\d?\d/
    :min
  when /\d\d\d\d\-\d?\d\-\d?\d \d?\d/
    :hour
  when /\d\d\d\d\-\d?\d\-\d?\d/
    :day
  when /\d\d\d\d\-\d?\d/
    :month
  when /\d\d\d\d/
    :year
  else
    raise ArgumentError, "Unacceptable date string #{date_string}"
  end
end

.end_date(en) ⇒ Object



61
62
63
64
65
66
67
# File 'lib/daru/date_time/index.rb', line 61

def end_date en
  if en.is_a?(String)
    date_time_from(en, determine_date_precision_of(en))
  else
    en
  end
end

.find_date_string_bounds(date_string) ⇒ Object



129
130
131
132
133
# File 'lib/daru/date_time/index.rb', line 129

def find_date_string_bounds date_string
  date_precision = determine_date_precision_of date_string
  date_time = date_time_from date_string, date_precision
  generate_bounds date_time, date_precision
end

.find_index_of_date(data, date_time) ⇒ Object

Raises:

  • (ArgumentError)


122
123
124
125
126
127
# File 'lib/daru/date_time/index.rb', line 122

def find_index_of_date data, date_time
  searched = data.bsearch { |d| d[0] >= date_time }
  raise(ArgumentError, "Cannot find #{date_time}") if searched.nil? || searched[0] != date_time

  searched[1]
end

.generate_bounds(date_time, date_precision) ⇒ Object



168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/daru/date_time/index.rb', line 168

def generate_bounds date_time, date_precision
  case date_precision
  when :year
    [
      date_time,
      DateTime.new(date_time.year,12,31,23,59,59)
    ]
  when :month
    [
      date_time,
      DateTime.new(date_time.year, date_time.month, ((date_time >> 1) - 1).day,
        23,59,59)
    ]
  when :day
    [
      date_time,
      DateTime.new(date_time.year, date_time.month, date_time.day,23,59,59)
    ]
  when :hour
    [
      date_time,
      DateTime.new(date_time.year, date_time.month, date_time.day,
        date_time.hour,59,59)
    ]
  when :min
    [
      date_time,
      DateTime.new(date_time.year, date_time.month, date_time.day,
        date_time.hour, date_time.min, 59)
    ]
  else # second or when precision is same as offset
    [date_time, date_time]
  end
end

.generate_data(start, en, offset, periods) ⇒ Object



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/daru/date_time/index.rb', line 78

def generate_data start, en, offset, periods
  data = []
  new_date = begin_from_offset?(offset, start) ? start : offset + start

  if periods.nil? # use end
    loop do
      break if new_date > en
      data << new_date
      new_date = offset + new_date
    end
  else
    periods.times do
      data << new_date
      new_date = offset + new_date
    end
  end

  data
end

.infer_offset(data) ⇒ Object



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/daru/date_time/index.rb', line 105

def infer_offset data
  possible_freq = data[1] - data[0]
  inferred = true
  data.each_cons(2) do |d|
    if d[1] - d[0] != possible_freq
      inferred = false
      break
    end
  end

  if inferred
    TIME_INTERVALS[possible_freq].new
  else
    nil
  end
end

.key_out_of_bounds?(key, data) ⇒ Boolean

Returns:

  • (Boolean)


211
212
213
214
215
216
217
218
219
220
221
# File 'lib/daru/date_time/index.rb', line 211

def key_out_of_bounds? key, data
  precision = determine_date_precision_of key
  date_time = date_time_from key, precision
  case precision
  when :year
    date_time.year < data[0][0].year || date_time.year > data[-1][0].year
  when :month
    (date_time.year < data[0][0].year && date_time.month < data[0][0].month) ||
      (date_time.year > data[-1][0].year and date_time.month > data[-1][0].month)
  end
end

.last_date(data) ⇒ Object



207
208
209
# File 'lib/daru/date_time/index.rb', line 207

def last_date data
  data.sort_by { |d| d[1] }.last
end

.offset_from_frequency(frequency) ⇒ Object

Generates a Daru::DateOffset object for generic offsets or one of the specialized classed within Daru::Offsets depending on the ‘frequency’ string.

Raises:

  • (ArgumentError)


30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/daru/date_time/index.rb', line 30

def offset_from_frequency frequency
  frequency = 'D' if frequency.nil?
  return frequency if frequency.is_a?(Daru::DateOffset)

  matched = /([0-9]*)(MONTH|YEAR|S|H|MB|ME|M|D|W|YB|YE)/.match(frequency)
  raise ArgumentError,
    "Invalid frequency string #{frequency}" if matched.nil?

  n             = matched[1] == '' ? 1 : matched[1].to_i
  offset_string = matched[2]
  offset_klass  = OFFSETS_HASH[offset_string]

  raise ArgumentError,
    "Cannont interpret offset #{offset_string}" if offset_klass.nil?

  if offset_string =~ /W/
    day = Regexp.new(Daru::DAYS_OF_WEEK.keys.join('|')).match(frequency).to_s
    return offset_klass.new(n, weekday: Daru::DAYS_OF_WEEK[day])
  end

  offset_klass.new(n)
end

.possibly_convert_to_date_time(data) ⇒ Object



203
204
205
# File 'lib/daru/date_time/index.rb', line 203

def possibly_convert_to_date_time data
  data[0].is_a?(String) ? data.map! { |e| DateTime.parse(e) } : data
end

.start_date(start) ⇒ Object



53
54
55
56
57
58
59
# File 'lib/daru/date_time/index.rb', line 53

def start_date start
  if start.is_a?(String)
    date_time_from(start, determine_date_precision_of(start))
  else
    start
  end
end

.verify_start_and_end(start, en) ⇒ Object

Raises:

  • (ArgumentError)


98
99
100
101
102
103
# File 'lib/daru/date_time/index.rb', line 98

def verify_start_and_end start, en
  raise ArgumentError, 'Start and end cannot be the same' if start == en
  raise ArgumentError, 'Start must be lesser than end'    if start > en
  raise ArgumentError,
    'Only same time zones are allowed' if start.zone != en.zone
end