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

JavascriptTime

Javascript Problem Overview


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

Javascript Solutions


Solution 1 - Javascript

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). //----

Solution 2 - Javascript

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;
}

Solution 3 - Javascript

##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

Solution 4 - Javascript

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);

Solution 5 - Javascript

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) )

Solution 6 - Javascript

I use these code:

function RoundUp(intervalMilliseconds, datetime){
    datetime = datetime || new Date();
    var modTicks = datetime.getTime() % intervalMilliseconds;
    var delta = modTicks === 0 ? 0  : datetime.getTime() - modTicks;
    delta += intervalMilliseconds;
    return new Date(delta);
}

function RoundDown(intervalMilliseconds, datetime){
    datetime = datetime || new Date();
    var modTicks = datetime.getTime() % intervalMilliseconds;
    var delta = modTicks === 0 ? 0  : datetime.getTime() - modTicks;
    return new Date(delta);
}

function Round(intervalMilliseconds, datetime){
    datetime = datetime || new Date();
    var modTicks = datetime.getTime() % intervalMilliseconds;
    var delta = modTicks === 0 ? 0  : datetime.getTime() - modTicks;
    var shouldRoundUp = modTicks > intervalMilliseconds/2;
    delta += shouldRoundUp ? intervalMilliseconds : 0;
    return new Date(delta);
}

Round to the nearest 5 minutes:

//with current datetime
var result = Round(5 * 60 * 1000);

//with a given datetime
var dt = new Date();
var result = Round(5 * 60 * 1000, dt);

Solution 7 - Javascript

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

Solution 8 - Javascript

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);

Solution 9 - Javascript

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));

Solution 10 - Javascript

This method is specifically for Vue.js, it takes a time, and returns to the nearest entered increment, I based this on an above answer, but this is for Vue specifically using echma-6 standards. It will return T:06:00:00, if you fed 06:05 into it. This is used specifically with vuetify's v-calendar to choose a time in weeklyor daily format.

This answer also adds the 0 for like 06 hrs. Which is where this differs from the above answers. If you change the 30 to 15

methods: {
  roundTimeAndFormat(datetime, roundTo) {
    const hrsMins = datetime.split(':')
    let min = ((((hrsMins[1] + 7.5) / roundTo) | 0) * roundTo) % 60
    let hr = (((hrsMins[1] / 105 + 0.5) | 0) + hrsMins[0]) % 24
    if (Number(hr) < 10) {
      hr = ('0' + hr).slice(-2)
    }
    if (min === 0) {
      min = ('0' + min).slice(-2)
    }
    return 'T' + hr + ':' + min + ':00'
  }
}

You would just call:

this.roundTimeAndFormat(dateTime, 15)

And you would get the time to the nearest 15min interval. If you enter, 11:01, you'd get T11:00:00

Solution 11 - Javascript

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?

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiondevploymentView Question on Stackoverflow
Solution 1 - JavascriptRobert KoritnikView Answer on Stackoverflow
Solution 2 - JavascriptAntoine DesboisView Answer on Stackoverflow
Solution 3 - JavascriptjoshuakcockrellView Answer on Stackoverflow
Solution 4 - JavascriptLazarusView Answer on Stackoverflow
Solution 5 - JavascriptSlaiView Answer on Stackoverflow
Solution 6 - JavascriptDanny SuView Answer on Stackoverflow
Solution 7 - JavascriptDanny HurlburtView Answer on Stackoverflow
Solution 8 - JavascriptRaja SekarView Answer on Stackoverflow
Solution 9 - JavascriptShubham RaiView Answer on Stackoverflow
Solution 10 - JavascriptdustbusterView Answer on Stackoverflow
Solution 11 - JavascriptSaiView Answer on Stackoverflow