Lance Pollard
Lance Pollard

Reputation: 79308

Iterating over Hours for 1 month in Ruby takes 15 seconds - What's the best way to iterate over intervals of time in Ruby?

If I iterate over 1 month of time to do something for each hour, it takes about 14 seconds using Range#step:

bm = Benchmark.measure do
  (Time.now..(Time.now + 1.month)).step(1.hour) { |hour| puts hour.inspect }
end
puts bm
=> 14.750000   0.060000  14.810000 ( 14.907838)

That's because it's iterating over every [second]? What is the best way to create and iterate over a range of times for each hour, from the beginning of the hour?

range == [...Wed Feb 09 11:00:00 -0600 2011, Wed Feb 09 12:00:00 -0600 2011, ...]

Upvotes: 2

Views: 2435

Answers (4)

Rimian
Rimian

Reputation: 38418

Here's something I wrote to iterate over days in rails.

def each_day(range, &block)
  values = []
  (range.first.to_i .. range.last.to_i).step(1.day) { |d| values << Time.at(d) }
  return values unless block_given?
  values.each { |val| yield(val) }
end

range = (Time.local(2012, 12, 31) .. Time.local(2013, 1, 1))

each_day(range) { |d| puts d.inspect }

Upvotes: 0

Michael Papile
Michael Papile

Reputation: 6856

Well a month of time is not a constant. You also have to deal with daylight savings time etc. So to iterate over a month (or any time span) by hour quickly and more accurately:

bm = Benchmark.measure do
  s_time = Time.local(2011,1,1)
  e_time = Time.local(2011,2,1)
  while(s_time < e_time)
    puts s_time.inspect
    s_time += 3600
  end
end

puts bm

0.010000   0.000000   0.010000 (  0.010531)

If you want to only display hours on top of hour between arbitrary times:

 s_time += s_time.to_i % 3600
 e_time -= e_time.to_i % 3600

Upvotes: 0

DanneManne
DanneManne

Reputation: 21180

This could be an alternative. Seems to be a lot quicker at least.

bm = Benchmark.measure do
  time = Time.now
  while time < (Time.now + 1.month)
    puts time.inspect
    time += 1.hour
  end
end
puts bm
=> 0.483000   0.000000   0.483000 (  0.546000)

Upvotes: 4

zetetic
zetetic

Reputation: 47548

t = Time.now
0.upto(1.month/1.hour) {|i| puts t+i*1.hour}

Note: assumes you have required activesupport for the 1.month and 1.hour. Also this gives you constant sized months (2592000 seconds), which rather limits its usefulness.

Upvotes: 2

Related Questions