31 votes

Iterate sur un objet Ruby Time avec delta

Existe-t-il un moyen d'itérer sur une plage de temps en Ruby, et de définir le delta ?

Voici une idée de ce que j'aimerais faire :

for hour in (start_time..end_time, hour)
    hour #=> Time object set to hour
end

Vous pouvez itérer sur les objets Time, mais cela renvoie chaque seconde entre les deux. Ce dont j'ai vraiment besoin, c'est d'un moyen de définir le décalage ou le delta (comme les minutes, les heures, etc.).

Est-ce intégré à Ruby, ou existe-t-il un plugin décent ?

55voto

Zach Langley Points 3523

Avant la version 1.9, vous pouviez utiliser Range#step :

(start_time..end_time).step(3600) do |hour|
  # ...
end

Cependant, cette stratégie est assez lente car elle appelle Time#succ 3600 fois. Au lieu de cela, comme l'a souligné dolzenko dans sa réponse, une solution plus efficace consiste à utiliser une simple boucle :

hour = start_time
while hour < end_time
  # ...
  hour += 3600
end

Si vous utilisez Rails, vous pouvez remplacer 3600 par 1.hour qui est nettement plus lisible.

39voto

dolzenko Points 2098

Si votre start_time y end_time sont en fait des instances de Time alors la solution avec l'utilisation de la classe Range#step serait extrêmement inefficace puisqu'il faudrait itérer sur chaque seconde de cet intervalle avec Time#succ . Si vous convertissez vos temps en nombres entiers, l'addition simple sera utilisée, mais de cette façon, vous obtiendrez quelque chose comme :

(start_time.to_i..end_time.to_i).step(3600) do |hour|
  hour = Time.at(hour)     
  # ...
end

Mais cela peut aussi être fait avec une boucle plus simple et plus efficace (c'est-à-dire sans toutes les conversions de type) :

hour = start_time
begin
  # ...      
end while (hour += 3600) < end_time

17voto

Xenofex Points 333

La méthode Range#step est très lente dans ce cas. Utilisez la méthode begin..end while, comme l'a indiqué dolzenko ici.

Vous pouvez définir une nouvelle méthode :

  def time_iterate(start_time, end_time, step, &block)
    begin
      yield(start_time)
    end while (start_time += step) <= end_time
  end

alors,

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

si dans les rails.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X