Reputation: 79308
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
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
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
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
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