36

I have a simple task where I want to take a starting date and an ending date and loop over the days/dates. This code is being used in my db:seed rake task. Currently, my code has gone through the following attempts.

(someModel.start_date.to_datetime..someModel.end_date.to_datetime).each { 
    |x| puts x 
}
 ......
(someModel.start_date...someModel.end_date).each { |x| puts x }

In each case, I get an error like this.

can't iterate from ActiveSupport::TimeWithZone
or 
can't iterate from DateTime

If anyone has any clue on how to iterate over a range of DateTimes I'd be greatly appreciative.

Black Dynamite
  • 4,067
  • 5
  • 40
  • 75

5 Answers5

32
start = someModel.start_date.to_datetime
finish = someModel.end_date.to_datetime
while(start < finish) do
  #bunch of awesome stuff
  start += 1.day
end
Chris Barretto
  • 9,379
  • 3
  • 42
  • 45
10

You must make sure that you are dealing with a Date object (by calling to_date), then everything works as expected:

start_date.to_date.upto(end_date.to_date) {|date| puts date }

Or with a range:

(start_date.to_date..end_date.to_date).to_a
collimarco
  • 34,231
  • 36
  • 108
  • 142
4

You can't iterate from DateTime. But you can iterate when start and end of interval are instances of Date. Convert them if possible.

And then look at these Date methods:

to use instead of each

vrybas
  • 1,719
  • 17
  • 12
0

If you want to iterate on the range you might consider a loop and step each day using something like someModel.start_date + 1.day.to_i

elixir
  • 104
  • 2
  • 6
0

Here's what we're doing to iterate by minutes over two TimeWithZones:

  # allow iteration over a set of TimeWithZones
  def self.time_map(range, step: 30.minutes, &block)
    result = []
    time = range.first
    max = range.last
    test = range.exclude_end? ? ->(t) { t < max } : ->(t) { t <= max }
    value = block_given? ? ->(t) { yield(t) } : ->(t) { t }
    while test.call(time) do
      result << value.call(time)
      time += step
    end
    result
  end
k00ka
  • 1,350
  • 2
  • 9
  • 10