Reputation: 52560
I need to round a DateTime
and also a Time
to the nearest 15 minute interval. My thought is to zero out the seconds and the milliseconds (do those exist in a DateTime
or Time
?) and maybe even nanoseconds? And then divide the number of minutes by 15, round that, then multiply the result by 15 and set that to be the minutes:
# zero out the seconds
time -= time.sec.seconds
# zero out the milliseconds (does that exist?)
# zero out the nanoseconds (less likely this exists)
minutes_should_be = (time.min / 15.to_f).round * 15
time += (minutes_should_be - time.min).minutes
So I guess my question is if there is a better way to do this and if milliseconds and nanoseconds exist in a DateTime
or Time
? There is a nsec method for nanoseconds, but I think that's the total nanoseconds since epoch.
Upvotes: 4
Views: 6476
Reputation: 46489
A generic rounding solution for DateTime, based on Tessi's answer:
class DateTime
def round(granularity=1.hour)
Time.at((self.to_time.to_i/granularity).round * granularity).to_datetime
end
end
Example usage:
DateTime.now.round 15.minutes
> Fri, 15 May 2015 11:15:00 +0100
Upvotes: 4
Reputation: 13574
The following should do the trick:
##
# rounds a Time or DateTime to the neares 15 minutes
def round_to_15_minutes(t)
rounded = Time.at((t.to_time.to_i / 900.0).round * 900)
t.is_a?(DateTime) ? rounded.to_datetime : rounded
end
The function converts the input to a Time
object, which can be converted to the seconds since the epoch with to_i
(this automatically strips nano-/milliseconds). Then we divide by 15 minutes (900 seconds) and round the resulting float. This automatically rounds the time to the nearest 15 minutes. Now, we just need to multiply the result by 15 minutes and convert it to a (date)time again.
round_to_15_minutes Time.new(2013, 9, 13, 0, 7, 0, "+02:00")
#=> 2013-09-13 00:00:00 +0200
round_to_15_minutes Time.new(2013, 9, 13, 0, 8, 0, "+02:00")
#=> 2013-09-13 00:15:00 +0200
round_to_15_minutes Time.new(2013, 9, 13, 0, 22, 29, "+02:00")
#=> 2013-09-13 00:15:00 +0200
round_to_15_minutes Time.new(2013, 9, 13, 0, 22, 30, "+02:00")
#=> 2013-09-13 00:30:00 +0200
round_to_15_minutes DateTime.now
#=> #<DateTime: 2013-09-13T01:00:00+02:00 ((2456548j,82800s,0n),+7200s,2299161j)>
Upvotes: 8
Reputation: 77786
I think this will work
def nearest15 minutes
((minutes / 60.0 * 4).round / 4.0 * 60).to_i
end
The idea, is
Some sample output
10.times do
n = [*1..200].sample
puts "%d => %d" % [n, nearest15(n)]
end
Output
85 => 90
179 => 180
54 => 60
137 => 135
104 => 105
55 => 60
183 => 180
184 => 180
46 => 45
92 => 90
Upvotes: 2