78

How do you round up/ round down a momentjs moment to nearest minute?

I have checked the docs, but there doesn't appear to be a method for this.

Note that I do not want a string rounded to the nearest minute, I want a moment returned (or modified in place, either is fine). I prefer not to have to convert to a string, and the convert back too.

Thanks.


As requested, here is some code:

var now = new moment(new Date());

if (now.seconds() > 0) {
    now.add('minutes', -1);
}

now.seconds(0);

as you can see, I have managed to manually round down the moment here, but it seems rather hacky. Just after a more elegant way of accomplishing this.

Henrik Andersson
  • 45,354
  • 16
  • 98
  • 92
bguiz
  • 27,371
  • 47
  • 154
  • 243

10 Answers10

119

To round up, you need to add a minute and then round it down. To round down, just use the startOf method.

Note the use of a ternary operator to check if the time should be rounded (for instance, 13:00:00 on the dot doesn't need to be rounded).

Round up/down to the nearest minute

var m = moment('2017-02-17 12:01:01');
var roundDown = m.startOf('minute');
console.log(roundDown.toString()); // outputs Tue Feb 17 2017 12:01:00 GMT+0000

var m = moment('2017-02-17 12:01:01');
var roundUp = m.second() || m.millisecond() ? m.add(1, 'minute').startOf('minute') : m.startOf('minute');
console.log(roundUp.toString());  // outputs Tue Feb 17 2017 12:02:00 GMT+0000

Round up/down to the nearest hour

var m = moment('2017-02-17 12:59:59');
var roundDown = m.startOf('hour');
console.log(roundDown.toString()); // outputs Tue Feb 17 2017 12:00:00 GMT+0000

var m = moment('2017-02-17 12:59:59');
var roundUp = m.minute() || m.second() || m.millisecond() ? m.add(1, 'hour').startOf('hour') : m.startOf('hour');
console.log(roundUp.toString());  // outputs Tue Feb 17 2017 13:00:00 GMT+0000
Liyali
  • 5,643
  • 2
  • 26
  • 40
  • 7
    This method for rounding up is not a proper [ceiling function](https://en.wikipedia.org/wiki/Floor_and_ceiling_functions): `12:00:00` if rounded up to the hour gives `13:00:00`. See [my answer](http://stackoverflow.com/a/37685886/2701578) for more details and a possible fix. – remeika Jun 07 '16 at 17:44
  • 1
    thanks for flagging this up @remeika — answer updated accordingly – Liyali Feb 09 '17 at 16:33
  • Why not use 'endOf' method (http://momentjs.com/docs/#/manipulating/end-of/)? It's available since the same version as 'startOf' – Kirill Gamazkov Jun 13 '17 at 12:19
  • @KirillGamazkov it's identical, you can do the same by doing it the other way around: `var roundUp = m.second() || m.millisecond() ? m.endOf('minute').add(1, 'millisecond') : m.startOf('minute');` – Liyali Jun 22 '17 at 14:43
  • 5
    @KirillGamazkov The [endOf](http://momentjs.com/docs/#/manipulating/end-of/) function creates values like "2019-10-11T18:59:59.999" which you may want to be "2019-10-11T19:00:00.000". – Benny Code Oct 11 '19 at 17:04
27

Partial answer:

To round down to nearest moment minute:

var m = moment();
m.startOf('minute');

However, the equivalent for rounding up, endOf, doesn't quite give the expected result.

mark
  • 1,953
  • 1
  • 24
  • 47
bguiz
  • 27,371
  • 47
  • 154
  • 243
24

Rounding to the nearest hour can be achieved by adding half an hour and then run .startOf('hour'). This is the same for any time measurement.

var now = moment();
// -> Wed Sep 30 2015 11:01:00
now.add(30, 'minutes').startOf('hour'); // -> Wed Sep 30 2015 11:31:00
// -> Wed Sep 30 2015 11:00:00

var now = moment();
// -> Wed Sep 30 2015 11:31:00
now.add(30, 'minutes').startOf('hour'); // -> Wed Sep 30 2015 12:01:00
// -> Wed Sep 30 2015 12:00:00
martinedwards
  • 5,577
  • 1
  • 33
  • 35
15

The roundTo feature could make it into a future release.

Examples:

moment().roundTo('minute', 15); // output: 12:45
moment().roundTo('minute', 15, 'down'); // output: 12:30
Tri Q Tran
  • 5,500
  • 2
  • 37
  • 58
  • 2
    Guess not. PR was closed. There is a [plugin](https://github.com/WebDevTmas/moment-round) though. – mpen Aug 30 '17 at 19:04
14

Rounding Down

Easy. As stated by many others, just use Moment.startOf:

var roundDown = moment('2015-02-17 12:59:59').startOf('hour');
roundDown.format('HH:mm:SS'); // 12:00:00

Importantly, this also works as expected:

var roundDown = moment('2015-02-17 12:00:00').startOf('hour');
roundDown.format('HH:mm:SS'); // 12:00:00

Rounding Up

Slightly trickier, if we want to round up with a proper ceiling function: for example, when rounding up by hour, we want 12:00:00 to round up to 12:00:00.

This does not work

var roundUp = moment('2015-02-17 12:00:00').add(1, 'hour').startOf('hour');
roundUp.format('HH:mm:SS'); // ERROR: 13:00:00

Solution

function roundUp(momentObj, roundBy){
  return momentObj.add(1, roundBy).startOf(roundBy);
}


var caseA = moment('2015-02-17 12:00:00');
roundUp(caseA, 'minute').format('HH:mm:SS'); // 12:00:00

var caseB = moment('2015-02-17 12:00:00.001');
roundUp(caseB, 'minute').format('HH:mm:SS'); // 12:01:00

var caseC = moment('2015-02-17 12:00:59');
roundUp(caseC, 'minute').format('HH:mm:SS'); // 12:01:00
Andrew
  • 5,839
  • 1
  • 51
  • 72
remeika
  • 1,075
  • 11
  • 16
  • 1
    The `momentObj.millisecond() != 1` check affects nothing: `moment('2015-02-17 12:00:00.001').subtract(1,'millisecond').add(1, 'minute').startOf('minute').format('HH:mm:SS') === moment('2015-02-17 12:00:00.001').add(1, 'minute').startOf('minute').format('HH:mm:SS') === '12:01:00'` – Finesse Oct 05 '19 at 11:32
  • @Finesse You are correct, though funnily enough the equivalence code you provided ends up evaluating to false, unless you omit the latter one. ^.^ Anyways this check is not needed because the start of for a millisecond is the same regardless of whether you add an extra millisecond. – Andrew Feb 03 '20 at 18:58
  • Sorry but truncate(x+1) is not equal to floor(x) when x is already a round number. Also `ss` should be lowercase. Maybe try with an updated version of moment. – Rivenfall Feb 11 '20 at 16:28
10

A more precise answer:

t.add(30, 'seconds').startOf('minute')

Case1: Rounding down if seconds < 30

t = moment(); //12:00:05
t.add(30, 'seconds').startOf('minute') //12:00:00

Case2: Rounding up if seconds >= 30

t = moment(); //12:00:33
t.add(30, 'seconds').startOf('minute') //12:01:00
viv
  • 166
  • 1
  • 11
4

I was searching for this same question and found a better solution: Use the third parameter in diff() function:

moment("2019-05-02 17:10:20").diff("2019-05-02 17:09:30","minutes",true)

By setting third parameter to true, you get the raw value as response that you can round by yourself using Math.round()

See JSFiddle: https://jsfiddle.net/2wqs4o0v/3/

Sjoerd Loeve
  • 231
  • 1
  • 5
1

Just another possibility:

const now = moment();
// -> Wed Sep 30 2015 11:57:20 GMT+0200 (CEST)
now.add(1, 'm').startOf('minute');
// -> Wed Sep 30 2015 11:58:00 GMT+0200 (CEST)
Manu Artero
  • 9,238
  • 6
  • 58
  • 73
1

This solution worked for me;

function round_up_to_nearest_hour(date = new Date()) {
   return moment(date).add(59, 'minutes').startOf('hour').toDate();
}
Mokky Miah
  • 1,213
  • 2
  • 11
  • 29
  • Not correct: `round_up_to_nearest_hour(new Date('2015-02-17T12:00:30'))` gives `12:00:00` instead of `13:00:00` – Finesse Oct 05 '19 at 11:38
  • @Finesse it worked for my purpose, not sure why it didn't work for you. No need to be rude and vote down, – Mokky Miah Oct 26 '19 at 10:50
  • 3
    I'm not rude. I've given an objective real life case for which your solution gives a wrong result (considering the question). Fix the solution and I'll revote it. – Finesse Oct 27 '19 at 03:43
0

The simplest solution so far:

function floor(time, floorBy = 'minute') {
  return time.startOf(floorBy);
}

function ceil(time, ceilBy = 'minute') {
  return time.subtract(1, 'millisecond').add(1, ceilBy).startOf(ceilBy);
}

// The solution is above. The code below is an optional test:

console.log(
  floor(moment('2019-01-01 12:00:00.000')).format('H:mm:ss.SSS') === '12:00:00.000',
   ceil(moment('2019-01-01 12:00:00.000')).format('H:mm:ss.SSS') === '12:00:00.000',
  floor(moment('2019-01-01 12:00:00.001')).format('H:mm:ss.SSS') === '12:00:00.000',
   ceil(moment('2019-01-01 12:00:00.001')).format('H:mm:ss.SSS') === '12:01:00.000',
  floor(moment('2019-01-01 12:15:16.876'), 'hour'  ).format('H:mm:ss.SSS') === '12:00:00.000',
   ceil(moment('2019-01-01 12:15:16.876'), 'hour'  ).format('H:mm:ss.SSS') === '13:00:00.000',
  floor(moment('2019-01-01 12:59:59.999'), 'second').format('H:mm:ss.SSS') === '12:59:59.000',
   ceil(moment('2019-01-01 12:59:59.999'), 'second').format('H:mm:ss.SSS') === '13:00:00.000',
  floor(moment('2019-01-01 12:00:00.025'), 'ms'    ).format('H:mm:ss.SSS') === '12:00:00.025',
   ceil(moment('2019-01-01 12:00:00.025'), 'ms'    ).format('H:mm:ss.SSS') === '12:00:00.025'
);
<script src="//cdn.jsdelivr.net/npm/moment@2.24.0/min/moment.min.js"></script>
Finesse
  • 9,793
  • 7
  • 62
  • 92