Итерация над объектом Ruby Time с дельта
Есть ли способ перебрать диапазон времени в Ruby и установить delta?
Вот идея того, что я хотел бы сделать:
for hour in (start_time..end_time, hour)
hour #=> Time object set to hour
end
Вы можете выполнять итерацию по объектам Time, но она возвращает каждую секунду между ними. Мне действительно нужно установить смещение или дельта (например, минуту, час и т.д.).
Является ли это встроенным в Ruby, или есть доступный плагин?
Ответы
Ответ 1
До 1.9 можно использовать Range#step
:
(start_time..end_time).step(3600) do |hour|
# ...
end
Однако эта стратегия довольно медленная, так как она назовёт Time#succ
3600 раз. Вместо,
как отметил dolzenko в его ответе, более эффективным решением является использование простой петли:
hour = start_time
while hour < end_time
# ...
hour += 3600
end
Если вы используете Rails, вы можете заменить 3600 на 1.hour
, что значительно читаемо.
Ответ 2
Если ваши start_time
и end_time
на самом деле являются экземплярами класса Time
, тогда решение с использованием Range#step
было бы крайне неэффективно, так как оно повторяло бы каждую секунду в этом диапазоне с помощью Time#succ
. Если вы конвертируете свое время в целые числа, будет использовано простое добавление, но таким образом вы получите что-то вроде:
(start_time.to_i..end_time.to_i).step(3600) do |hour|
hour = Time.at(hour)
# ...
end
Но это также можно сделать с помощью более простого и эффективного (т.е. без всех преобразований типов):
hour = start_time
begin
# ...
end while (hour += 3600) < end_time
Ответ 3
Метод шага диапазона # в этом случае очень медленный. Используйте begin..end while, как dolzenko отправил здесь.
Вы можете определить новый метод:
def time_iterate(start_time, end_time, step, &block)
begin
yield(start_time)
end while (start_time += step) <= end_time
end
то
start_time = Time.parse("2010/1/1")
end_time = Time.parse("2010/1/31")
time_iterate(start_time, end_time, 1.hour) do |t|
puts t
end
если в рельсах.