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