Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

rounding a Rails DateTime to the nearest 15 minute interval

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.

like image 577
at. Avatar asked Dec 15 '22 06:12

at.


2 Answers

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.

Example values:

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)>
like image 173
tessi Avatar answered Feb 01 '23 23:02

tessi


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
like image 34
mahemoff Avatar answered Feb 02 '23 00:02

mahemoff