Is there an easy way to round a Time down to the nearest 15 minutes?
This is what I'm currently doing. Is there an easier way to do it?
t = Time.new
rounded_t = Time.local(t.year, t.month, t.day, t.hour, t.min/15*15)
Is there an easy way to round a Time down to the nearest 15 minutes?
This is what I'm currently doing. Is there an easier way to do it?
t = Time.new
rounded_t = Time.local(t.year, t.month, t.day, t.hour, t.min/15*15)
You said "round down", so I'm not sure if you're actually looking for the round or the floor, but here's the code to do both. I think something like this reads really well if you add round_off and floor methods to the Time class. The added benefit is that you can more easily round by any time partition.
require 'active_support/core_ext/numeric' # from gem 'activesupport'
class Time
# Time#round already exists with different meaning in Ruby 1.9
def round_off(seconds = 60)
Time.at((self.to_f / seconds).round * seconds).utc
end
def floor(seconds = 60)
Time.at((self.to_f / seconds).floor * seconds).utc
end
end
t = Time.now # => Thu Jan 15 21:26:36 -0500 2009
t.round_off(15.minutes) # => Thu Jan 15 21:30:00 -0500 2009
t.floor(15.minutes) # => Thu Jan 15 21:15:00 -0500 2009
Note: ActiveSupport was only necessary for the pretty 15.minutes argument. If you don't want that dependency, use 15 * 60 instead.
I am not very familiar with the syntax of ruby but you can round down to the nearest 15 minutes using modulo. (i.e. x - (x modulo 15)). I would guess the syntax would be something like
t.min - ( t.min % 15)
This will make your set of possible values 0, 15, 30, and 45. Assuming 0 <= t.min <= 59.
Since Ruby allows arithmetic (in seconds) on Times, you can just do this:
t = Time.new
rounded_t = t-t.sec-t.min%15*60
Chuck's answer, while elegant, will run you into trouble if you try to compare values derived in this way; the usecs are not zeroed out.
Shalmanese' answer takes care of that, or Chuck's can be modified as:
t = Time.new
truncated_t = Time.at(t.to_i - t.sec - t.min % 15 * 60)
Your current evaluation using
min / 15 * 15
is only truncating the min, so
15 => 15
16 => 15
..
29 => 15
30 => 30
Which is not 'rounding'.
You can approximate rounding in a bad-way with
(( min + 7.5 ) / 15).to_i * 15
Or, using internals:
( min.to_f / 15 ).round * 15
If you're using ActiveSupport, then you can use some of its time helpers.
t = Time.now
t.at_beginning_of_hour + (t.min - t.min % 15).minutes