How to round time to the nearest quarter hour in JavaScript?

For example:

Given time: 08:22 => Rounded to: 08:15

Given time: 08:23 => Rounded to: 08:30

Should be pretty simple. But all I was able to produce is lengthy, not very good code to solve the issue. My mind's just gone blank.

Regards

Answers:

Answer

Given that you have hours and minutes in variables (if you don't you can get them from the Date instance anyway by using Date instance functions):

var m = (parseInt((minutes + 7.5)/15) * 15) % 60;
var h = minutes > 52 ? (hours === 23 ? 0 : ++hours) : hours;

minutes can as well be calculated by using Math.round():

var m = (Math.round(minutes/15) * 15) % 60;

or doing it in a more javascript-sophisticated expression without any functions:

var m = (((minutes + 7.5)/15 | 0) * 15) % 60;
var h = ((((minutes/105) + .5) | 0) + hours) % 24;

You can check the jsPerf test that shows Math.round() is the slowest of the three while mainly the last one being the fastest as it's just an expression without any function calls (no function call overhead i.e. stack manipulation, although native functions may be treated differently in Javascript VM). //----

Answer

This function round the time to the nearest quarter hour.

function roundTimeQuarterHour(time) {
    var timeToReturn = new Date(time);

    timeToReturn.setMilliseconds(Math.round(timeToReturn.getMilliseconds() / 1000) * 1000);
    timeToReturn.setSeconds(Math.round(timeToReturn.getSeconds() / 60) * 60);
    timeToReturn.setMinutes(Math.round(timeToReturn.getMinutes() / 15) * 15);
    return timeToReturn;
}
Answer

With Time String

Here is a method that will round a time string like the one you presented. Eg "08:22"

let roundTime = (time, minutesToRound) => {

    let [hours, minutes] = time.split(':');
    hours = parseInt(hours);
    minutes = parseInt(minutes);

    // Convert hours and minutes to time in minutes
    time = (hours * 60) + minutes; 

    let rounded = Math.round(time / minutesToRound) * minutesToRound;
    let rHr = ''+Math.floor(rounded / 60)
    let rMin = ''+ rounded % 60

    return rHr.padStart(2, '0')+':'+rMin.padStart(2, '0')
}

// USAGE //

// Round time to 15 minutes
roundTime('8:07', 15); // "08:00"
roundTime('7:53', 15); // "08:00"
roundTime('7:52', 15); // "07:45"

With Hours and Minutes Already Split Up

You can use this method if you don't need to parse out the hour and minute strings like your example shows

let roundTime = (hours, minutes, minutesToRound) => {

    // Convert hours and minutes to minutes
    time = (hours * 60) + minutes; 
    let rounded = Math.round(time / minutesToRound) * minutesToRound;

    let roundedHours = Math.floor(rounded / 60)
    let roundedMinutes = rounded % 60

    return { hours: roundedHours, minutes: roundedMinutes }
}

// USAGE //

// Round time to 15 minutes
roundTime(7, 52, 15); // {hours: 7, minutes: 45}
roundTime(7, 53, 15); // {hours: 8, minutes: 0}
roundTime(1, 10, 15); // {hours: 1, minutes: 15}

With Existing Date Object

Or, if you are looking to round an already existing date object to the nearest x minutes, you can use this method.

If you don't give it any date it will round the current time. In your case, you can round to the nearest 15 minutes.

let getRoundedDate = (minutes, d=new Date()) => {

  let ms = 1000 * 60 * minutes; // convert minutes to ms
  let roundedDate = new Date(Math.round(d.getTime() / ms) * ms);

  return roundedDate
}


// USAGE //

// Round existing date to 5 minutes
getRoundedDate(15, new Date()); // 2018-01-26T00:45:00.000Z

// Get current time rounded to 30 minutes
getRoundedDate(30); // 2018-01-26T00:30:00.000Z
Answer

The code here is a little verbose but I'm sure you'll see how you could combine the lines to make this shorter. I've left it this way to clearly show the steps:

var now = new Date();
var mins = now.getMinutes();
var quarterHours = Math.round(mins/15);
if (quarterHours == 4)
{
    now.setHours(now.getHours()+1);
}
var rounded = (quarterHours*15)%60;
now.setMinutes(rounded);
document.write(now);
Answer

Divide by 9e5 milliseconds (15 * 60 * 1000), round, and multiply back by 9e5 :

const roundToQuarter = date => new Date(Math.round(date / 9e5) * 9e5)

console.log( roundToQuarter(new Date("1999-12-31T23:52:29.999Z")) ) // 1999-12-31T23:45:00

console.log( roundToQuarter(new Date("1999-12-31T23:52:30.000Z")) ) // 2000-01-01T00:00:00

console.log( roundToQuarter(new Date) )

Answer

Another one with date-fns (not mandatory)

import {getMinutes, setMinutes, setSeconds, setMilliseconds} from 'date-fns'

let date = new Date();
let min = getMinutes(date);
let interval = 3  // in minutes
let new_min = min - min%interval + interval;
let new_date = setMilliseconds(setSeconds(setMinutes(date,new_min),0),0)

console.log('Orignal Date : ' + date);
console.log('Original Minute : ' + min);
console.log('New Minute : ' + new_min);
console.log('New Date : ' + new_date);
Answer

Might help others. For any language. Mainly trick with round function.

roundedMinutes = yourRoundFun(Minutes / interval) * interval

E.g. The interval could be 5 minutes, 10 minutes, 15 minutes, 30 minutes. Then rounded minutes can be reset to the respective date.

yourDateObj.setMinutes(0) 
yourDateObj.setMinutes(roundedMinutes)

also if required then

yourDateObj.setSeconds(0) 
yourDateObj.setMilliSeconds(0) 

Simple?

Answer

There is an NPM package @qc/date-round that can be used. Given that you have a Date instance to be rounded

import { round } from '@qc/date-round'

const dateIn = ...; // The date to be rounded
const interval = 15 * 60 * 1000; // 15 minutes (aka quarter hour)
const dateOut = round(dateIn, interval)

Then you can use date-fns to format the date

import format from 'date-fns/format';

console.log(format(dateOut, 'HH:mm')) // 24-hr
console.log(format(dateOut, 'hh:mm a')) // 12-hr
Answer

Pass the interval in milliseconds get the next cycle in roundUp order

Example if I want next 15 minute cycle from current time then call this method like *calculateNextCycle(15 * 60 * 1000);*

Samething for quarter hour pass the interval

function calculateNextCycle(interval) {
    const timeStampCurrentOrOldDate = Date.now();
    const timeStampStartOfDay = new Date().setHours(0, 0, 0, 0);
    const timeDiff = timeStampCurrentOrOldDate - timeStampStartOfDay;
    const mod = Math.ceil(timeDiff / interval);
    return new Date(timeStampStartOfDay + (mod * interval));
}

console.log(calculateNextCycle(15 * 60 * 1000));

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.