Jochen
Jochen

Reputation: 1853

Ruby iterate over hours

Let's say I have some user input with start and end hours:

How do I display all the hours between those 2? So from 09 to 23, 0, and then to 1.

There are easy cases:

That's just a matter of ((start_hour.to_i)..(end_hour.to_i)).select { |hour| }

Upvotes: 1

Views: 214

Answers (4)

Stefan
Stefan

Reputation: 114188

With a simple condition:

def hours(from, to)
  if from <= to
    (from..to).to_a
  else
    (from..23).to_a + (0..to).to_a
  end
end

hours(1, 9)
#=> [1, 2, 3, 4, 5, 6, 7, 8, 9]

hours(9, 1)
#=> [9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 0, 1]

You could also use the shorter, but more cryptic [*from..23, *0..to] notation.

Upvotes: 0

astreal
astreal

Reputation: 3513

You could do a oneliner (0..23).to_a.rotate(start_h)[0...end_h - start_h]

def hours_between(start_h, end_h)
    (0..23).to_a.rotate(start_h)[0...end_h - start_h]
end

hours_between(1, 4)
# [1, 2, 3]
hours_between(4, 4)
# []
hours_between(23, 8)
# [23, 0, 1, 2, 3, 4, 5, 6, 7]

Don't forget to sanitize the input (That they are number between 0 and 23) :)

If you want the finishing hour use .. instead of ... => [0..end_h - start_h]

If you care about performance or want something evaluated lazily you can also do the following (reading the code is really clear):

(0..23).lazy.map {|h| (h + start_h) % 24 }.take_while { |h| h != end_h }

Upvotes: 1

tadman
tadman

Reputation: 211610

This can be solved with a custom Enumerator implementation:

def hours(from, to)
  Enumerator.new do |y|
    while (from != to)
      y << from
      from += 1
      from %= 24
    end
    y << from
  end
end

That gives you something you can use like this:

hours(9, 1).each do |hour|
  puts hour
end

Or if you want an Array:

hours(9,1).to_a
#=> [9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 0, 1]

Upvotes: 3

alexanderbird
alexanderbird

Reputation: 4198

https://stackoverflow.com/a/6784628/3012550 shows how to iterate over the number of hours in the distance between two times.

I would use that, and at each iteration use start + i.hours

def hours(number)
  number * 60 * 60
end

((end_time - start_time) / hours(1)).round.times do |i|
  print start_time + hours(i)
end

Upvotes: -1

Related Questions