[javascript] How to use format() on a moment.js duration?

Is there any way I can use the moment.js format method on duration objects? I can't find it anywhere in the docs and it doesn't seen to be an attribute on duration objects.

I'd like to be able to do something like:

var diff = moment(end).unix() - moment(start).unix();
moment.duration(diff).format('hh:mm:ss')

Also, if there are any other libraries which can easily accommodate this sort of functionality, I'd be interested in recommendations.

Thanks!

This question is related to javascript momentjs

The answer is


var diff = moment(end).unix() - moment(start).unix();
moment.utc(moment.duration(diff).asMilliseconds()).format("HH:mm:ss.SSS");

Use moment-duration-format.

Client Framework (ex: React)

import moment from 'moment';
import momentDurationFormatSetup from 'moment-duration-format';
momentDurationFormatSetup(moment);

const breakLengthInMinutes = moment.duration(breakLengthInSeconds, 's').format('m');

Server (node.js)

const moment = require("moment-timezone");
const momentDurationFormatSetup = require("moment-duration-format");

momentDurationFormatSetup(moment);

const breakLengthInMinutes = moment.duration(breakLengthInSeconds, 's').format('m');

// set up
let start = moment("2018-05-16 12:00:00"); // some random moment in time (in ms)
let end = moment("2018-05-16 12:22:00"); // some random moment after start (in ms)
let diff = end.diff(start);

// execution
let f = moment.utc(diff).format("HH:mm:ss.SSS");
alert(f);

Have a look at the JSFiddle


If all hours must be displayed (more than 24) and if '0' before hours is not necessary, then formatting can be done with a short line of code:

Math.floor(duration.as('h')) + moment.utc(duration.as('ms')).format(':mm:ss')

import * as moment from 'moment'
var sleep = require('sleep-promise');

(async function () {
    var t1 = new Date().getTime();
    await sleep(1000); 
    var t2 = new Date().getTime();
    var dur = moment.duration(t2-t1); 
    console.log(`${dur.hours()}h:${dur.minutes()}m:${dur.seconds()}s`);
})();

0h:0m:1s

This works for me:

moment({minutes: 150}).format('HH:mm') // 01:30

If you're willing to use a different javascript library, numeral.js can format seconds as follows (example is for 1000 seconds):

var string = numeral(1000).format('00:00');
// '00:16:40'

How about native javascript?

var formatTime = function(integer) {
    if(integer < 10) {
        return "0" + integer; 
    } else {
        return integer;
    }
}

function getDuration(ms) {
    var s1 = Math.floor(ms/1000);
    var s2 = s1%60;
    var m1 = Math.floor(s1/60);
    var m2 = m1%60;
    var h1 = Math.floor(m1/60);
    var string = formatTime(h1) +":" + formatTime(m2) + ":" + formatTime(s2);
    return string;
}

This can be used to get the first two characters as hours and last two as minutes. Same logic may be applied to seconds.

_x000D_
_x000D_
/**_x000D_
     * PT1H30M -> 0130_x000D_
     * @param {ISO String} isoString_x000D_
     * @return {string} absolute 4 digit number HH:mm_x000D_
     */_x000D_
_x000D_
    const parseIsoToAbsolute = (isoString) => {_x000D_
    _x000D_
      const durations = moment.duration(isoString).as('seconds');_x000D_
      const momentInSeconds = moment.duration(durations, 'seconds');_x000D_
    _x000D_
      let hours = momentInSeconds.asHours().toString().length < 2_x000D_
        ? momentInSeconds.asHours().toString().padStart(2, '0') : momentInSeconds.asHours().toString();_x000D_
        _x000D_
      if (!Number.isInteger(Number(hours))) hours = '0'+ Math.floor(hours);_x000D_
    _x000D_
      const minutes = momentInSeconds.minutes().toString().length < 2_x000D_
        ? momentInSeconds.minutes().toString().padEnd(2, '0') : momentInSeconds.minutes().toString();_x000D_
    _x000D_
      const absolute = hours + minutes;_x000D_
      return absolute;_x000D_
    };_x000D_
    _x000D_
    console.log(parseIsoToAbsolute('PT1H30M'));
_x000D_
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment-with-locales.min.js"></script>_x000D_
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>_x000D_
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
_x000D_
_x000D_
_x000D_


Based on ni-ko-o-kin's answer:

meassurements = ["years", "months", "weeks", "days", "hours", "minutes", "seconds"];
withPadding = (duration) => {
    var step = null;
    return meassurements.map((m) => duration[m]()).filter((n,i,a) => {
        var nonEmpty = Boolean(n);
        if (nonEmpty || step || i >= a.length - 2) {
            step = true;
        }
        return step;
    }).map((n) => ('0' + n).slice(-2)).join(':')
}

duration1 = moment.duration(1, 'seconds');
duration2 = moment.duration(7200, 'seconds');
duration3 = moment.duration(604800, 'seconds');

withPadding(duration1); // 00:01
withPadding(duration2); // 02:00:00
withPadding(duration3); // 01:07:00:00:00

if diff is a moment

var diff = moment(20111031) - moment(20111010);
var formated1 = moment(diff).format("hh:mm:ss");
console.log("format 1: "+formated1);

const duration = moment.duration(62, 'hours');
const n = 24 * 60 * 60 * 1000;
const days = Math.floor(duration / n);
const str = moment.utc(duration % n).format('H [h] mm [min] ss [s]');
console.log(`${days > 0 ? `${days} ${days == 1 ? 'day' : 'days'} ` : ''}${str}`);

Prints:

2 days 14 h 00 min 00 s


To format moment duration to string

var duration = moment.duration(86400000); //value in milliseconds
var hours = duration.hours();
var minutes = duration.minutes();
var seconds = duration.seconds();
var milliseconds = duration.milliseconds();

var date = moment().hours(hours).minutes(minutes).seconds(seconds).millisecond(milliseconds);
if (is12hr){
    return date.format("hh:mm:ss a");
}else{
    return date.format("HH:mm:ss");
}

My solution that does not involve any other library and it works with diff > 24h

var momentInSeconds = moment.duration(n,'seconds')
console.log(("0" + Math.floor(momentInSeconds.asHours())).slice(-2) + ':' + ("0" + momentInSeconds.minutes()).slice(-2) + ':' + ("0" + momentInSeconds.seconds()).slice(-2))

Use this line of code:

moment.utc(moment.duration(4500, "seconds").asMilliseconds()).format("HH:mm:ss")

moment.duration(x).format() has been deprecated. You can usemoment.utc(4366589).format("HH:mm:ss") to get the desired response.

_x000D_
_x000D_
console.log(moment.utc(4366589).format("HH:mm:ss"))
_x000D_
<script src="https://momentjs.com/downloads/moment.js"></script>_x000D_
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
_x000D_
_x000D_
_x000D_


The best scenario for my particular use case was:

var duration = moment.duration("09:30"),
    formatted = moment.utc(duration.asMilliseconds()).format("HH:mm");

This improves upon @Wilson's answer since it does not access private internal property _data.


I needed to do this for work as a requirement to display the hours in this format. At first I tried this.

moment.utc(totalMilliseconds).format("HH:mm:ss")

However anything over 24 hours and the hours reset to 0. But the minutes and seconds were accurate. So I used only that part for the minutes and seconds.

var minutesSeconds = moment.utc(totalMilliseconds).format("mm:ss")

Now all I need is the total hours.

var hours = moment.duration(totalMilliseconds).asHours().toFixed()

And to get that format that we all want we just glue it together.

var formatted = hours + ":" + minutesSeconds

if totalMilliseconds is 894600000 this will return 249:30:00.

Hope that helped. Leave any questions in the comments. ;)


I use the classic format function in these cases:

var diff = moment(end).unix() - moment(start).unix();

//use unix function instead of difference
moment.unix(diff).format('hh:mm:ss')

This is a hack because the time diff is treated as a standard moment date, an early epoch date time, but it doesn't matter to our goal and you don't need any plugin


if you use angular add this to your filters:

.filter('durationFormat', function () {
    return function (value) {
        var days = Math.floor(value/86400000);
        value = value%86400000;
        var hours = Math.floor(value/3600000);
        value = value%3600000;
        var minutes = Math.floor(value/60000);
        value = value%60000;
        var seconds = Math.floor(value/1000);
        return (days? days + ' days ': '') + (hours? hours + ' hours ': '') + (minutes? minutes + ' minutes ': '') + (seconds? seconds + ' seconds ': '')
    }
})

usage example

<div> {{diff | durationFormat}} </div>

Use this plugin Moment Duration Format.

Example:

moment.duration(123, "minutes").format("h:mm");

If you use Angular >2, I made a Pipe inspired by @hai-alaluf answer.

import {Pipe, PipeTransform} from "@angular/core";

@Pipe({
  name: "duration",
})

export class DurationPipe implements PipeTransform {

  public transform(value: any, args?: any): any {

    // secs to ms
    value = value * 1000;
    const days = Math.floor(value / 86400000);
    value = value % 86400000;
    const hours = Math.floor(value / 3600000);
    value = value % 3600000;
    const minutes = Math.floor(value / 60000);
    value = value % 60000;
    const seconds = Math.floor(value / 1000);
    return (days ? days + " days " : "") +
      (hours ? hours + " hours " : "") +
      (minutes ? minutes + " minutes " : "") +
      (seconds ? seconds + " seconds " : "") +
      (!days && !hours && !minutes && !seconds ? 0 : "");
  }
}

How to correctly use moment.js durations? | Use moment.duration() in code

First you need to import moment and moment-duration-format.

import moment from 'moment';
import 'moment-duration-format';

Then, use duration function. Let us apply the above example: 28800 = 8 am.

moment.duration(28800, "seconds").format("h:mm a");

Well, you do not have above type error. Do you get a right value 8:00 am ? No…, the value you get is 8:00 a. Moment.js format is not working as it is supposed to.

The solution is to transform seconds to milliseconds and use UTC time.

moment.utc(moment.duration(value, 'seconds').asMilliseconds()).format('h:mm a')

All right we get 8:00 am now. If you want 8 am instead of 8:00 am for integral time, we need to do RegExp

const time = moment.utc(moment.duration(value, 'seconds').asMilliseconds()).format('h:mm a');
time.replace(/:00/g, '')

I use:

var duration = moment.duration("09:30");
var str = moment(duration._data).format("HH:mm");

And I get "09:30" in var str.


You don't need .format. Use durations like this:

const duration = moment.duration(83, 'seconds');
console.log(duration.minutes() + ':' +duration.seconds());
// output: 1:23

I found this solution here: https://github.com/moment/moment/issues/463

EDIT:

And with padding for seconds, minutes and hours:

const withPadding = (duration) => {
    if (duration.asDays() > 0) {
        return 'at least one day';
    } else {
        return [
            ('0' + duration.hours()).slice(-2),
            ('0' + duration.minutes()).slice(-2),
            ('0' + duration.seconds()).slice(-2),
        ].join(':')
    }
}

withPadding(moment.duration(83, 'seconds'))
// 00:01:23

withPadding(moment.duration(6048000, 'seconds'))
// at least one day

convert duration to ms and then to moment:

moment.utc(duration.as('milliseconds')).format('HH:mm:ss')

You can use numeral.js to format your duration:

numeral(your_duration.asSeconds()).format('00:00:00') // result: hh:mm:ss