Moment: Duration missing features

Created on 10 Oct 2012  ·  186Comments  ·  Source: moment/moment

I'm working on a project and momentjs is really useful for date manipulation so thanks for that.

To give you an example, we're making somekind of store for plane tickets. The duration.humanize() function is way to imprecise for us.

For example when leaving at: 12:00 and landing at 13:30. It will round it to 2 hours. But we need some kind of granularity which is missing from momentjs.

humanize could default to 1 level of precision starting from the highest value.

// 1:30
duration.humanize()
2 hour
duration.humanize({precision: 2})
1 hour 30 minutes
duration.humanize({precision: 3})
1 hour 30 minutes 0 seconds

The second problem is when there is the number 0. Momentjs translates it as "few seconds". I'm not so sure how it could be achieved but it would be cool to have some kind of formatting.

// 3 days and 0 minutes
duration.format('D [and] M')
> 3 days and 0 minutes
duration.format('H [and] M')
> 72 hours and 0 minutes
duration.format('H [and] m')
> 72 hours and few minutes

That way the highest value could be mapped in the format. So even if there is 1 year, the format tells us how to display it correctly. I'd be happy to push a commit for that because it's very useful and having to do it by hand when momentjs already handle localization feels bad.

New Feature

Most helpful comment

2019, still in need of this feature.

All 186 comments

+1 on this request

@llacroix, would you be interested in writing a pull request for this?

Yes probably, i'll try to find time for that. Adding it to momentjs will probably save myself and others time in the long run. Currently this forces me to create some kind of mess everywhere and it's not perfect. Fixing momentjs seems more appropriate.

But we should probably discuss a bit more about what kind of format should be done. For example, should 0 values be displayed or not.

4 hours 20 seconds or 0 days 4 hours 0 minutes 20 seconds

Months would be 30 days, a year 365.

And what formats other than year, month, week, day, minute, second and millisecond should exist.

+1 for this
But yes, formatting is a key problem here. Humanize and format are definitely both needed.
Some suggestions for humanize behaviour :
// 1:30
duration.humanize();
1 hour 30 minutes
duration.humanize({round: "hours"})
2 hours
duration.humanize({round: "minutes"})
1 hour 30 minutes
duration.humanize({round: "seconds"})
1 hour 30 minutes 0 seconds

If round is not explicitely defined, I think the highest unity whose value is zero and all the units smaller than it should be omitted.

// 1 hour 0 minutes 45 seconds
duration.humanize() --> 1 hour
// 1 hour 1 minutes 0 seconds
duration.humanize() --> 1 hour and 1 minute
// 1 hour 1 minutes 10 seconds
duration.humanize() --> 1 hour 1 minute and 10 seconds

Also, the "and" separator should be used for the last join, preceeded by whitespaces
2 months 6 days 7 hours and 36 minutes

This is how I imagine that the function should behave by default

Here's my suggestion for the signature and implementation.

var duration = moment.duration({
    hours : 1,
    minutes : 0,
    seconds : 20,
    milliseconds : 0
});
duration.countdown(); // 1 hour 0 minutes 20 seconds
duration.countdown(1); // 1 hour
duration.countdown(2); // 1 hour and 0 minutes
duration.countdown(3); // 1 hour 0 minutes and 20 seconds

As @sylvainpolletvillard suggested, we may want to add a parameter for trimming off zeroed values. Maybe something like this.

duration.countdown(3); // 1 hour 0 minutes and 1 second
duration.countdown(3, true); // 1 hour

We may also want to add a parameter for the suffix like moment.fromNow(Boolean).

duration.countdown(3); // 1 hour 0 minutes and 1 second ago
duration.countdown(3, null, true); // 1 hour ago

We can build this somewhat easily for English, but concatenating all these strings correctly in all different languages will be very tricky.

We will probably have to create callbacks for languages to concatenate strings themselves. These rules will probably be very complex (I'm looking at you, hungarian).

I think the best way to pass these values would be something like the following.

var keys    = [     "h",        "mm",          "s"],
    values  = [       1,           0,           20],
    strings = ["1 hour", "0 minutes", "20 seconds"];

lang.countdown(keys, values, strings, addSuffix);

Then the English translation would be something like this:

lang.countdown = function (keys, values, strings, addSuffix) {
    var i, output = "";

    for (i = 0; i < strings.length; i++) {
        if (i === strings.length - 1 && strings.length > 1) {
            output += "and ";
        }
        output += strings[i] + " ";
    }
    if (addSuffix) {
        output += "ago";
    }
}

All in all, this becomes an incredibly complex addition which would require 33 translation functions and a bunch more code in core. Also, I'm not sure how often it would be used, so it's adding all that bloat for everyone else.

Perhaps this would be best moved to a plugin?

Going back to the discussion on formatting the duration I think it would be great if something like this were possible -

moment.duration(9483000).format('d h m s') // 1 day 2 hours 20 minutes 30 seconds  
moment.duration(9483000).format('h m s') // 26 hours 20 minutes 30 seconds 
//etc...  

Maybe providing a boolean parameter in the format method to determine whether 0 values were shown or not?

CLDR has a list formatting scheme and data, which might be able to be used for many languages, probably many languages would still need custom callbacks though:

http://cldr.unicode.org/development/development-process/design-proposals/list-formatting

I'm pretty for the format function. Since implementing translation of multiple languages might be quite hard. Using formats should be quite easy to implement.

Let say you want

moment.duration(9483000).format('d h m s') // 1 day 2 hours 20 minutes and 30 seconds  
// English  => 'd h m [and] s' 1 day 2 hours 20 minutes and 30 seconds
// French   => 'd, h, m [et] s'   1 jour, 2 heures, 20 minutes et 30 secondes
// Russian  => 'd h m [и] s'   1 день 2 часа 30 минут и 30 секунд

No need for special callbacks but just special format strings.

The proposed duration.countdown() and duration.countdown(1) methods are exactly what I'm looking for (i.e. what I'm doing now in my own code).

Meanwhile, is there a way to extend the Duration prototype?

The duration prototype is exposed via moment.duration.fn similar to moment.fn.

I have been working on something similar last year on #143/#192. Tim suggested a plugin but I never took the time to do it.

I was about to do reboot my work. I had to update to new concepts such as duration objects etc... I was this ticket and other ones. Now I'm struggling on wether it is still needed and if yes how should we implement that.

I don't want to step on one's shoes so le met know if I can help. Who is working on that issue right now?

My code was able to format to consecutive units and non consecutive units like that :

test.equal(moment([2012, 0, 1]).diff([2011, 0, 1], 'years\\y'), "1y");
test.equal(moment([2012, 0, 1]).diff([2011, 0, 1], 'months[m]'), "12m");
test.equal(moment([2016, 0, 20]).diff([2011, 10, 1], 'months [months] days [days]'), "50 months 19 days");
test.equal(moment([2016, 0, 20]).diff([2011, 10, 1], 'years \\y months \\M days \\d'), "4 y 2 M 19 d");
test.equal(moment([2016, 0, 20]).diff([2011, 10, 1], 'years[y] days[d]'), "4y 80d");
test.equal(moment([2016, 0, 20]).diff([2011, 10, 1], 'years [years] weeks [weeks]'), "4 years 11 weeks");
test.equal(moment([2016, 0, 20]).diff([2011, 10, 1], 'years\\y weeks\\w [and] days [days]'), "4y 11w and 3 days");
test.equal(moment([2016, 0, 20]).diff([2011, 10, 1], 'days\\d'), "1541d");

It didn't handle units that weren't in order like 'days years'. It also didn't handle removing zero values.

That looks awesome, exactly the kind of thing I was hoping for!

This is definitely a needed feature for everyone.

Need this!

As a possible stopgap for some of you, I've created a simple plugin that allows you to use countdown.js directly from Moment:

moment("1982-5-25").countdown().toString(); // => '30 years, 10 months, 14 days, 2 hours, 23 minutes, and 50 seconds'

It passes through any Countdown options you pass it, like what units to use and with how much precision (you can look at the Countdown docs). Anyway, the plugin is here: https://github.com/icambron/moment-countdown

@icambron thanks for your countribuiton! It's very helpful!

I've just started using moment.js and pretty quickly came across this exact problem. This is the code I used to solve it:

moment.duration.fn.format = function (input) {
    var output = input;
    var milliseconds = this.asMilliseconds();
    var totalMilliseconds = 0;
    var replaceRegexps = {
        years: /Y(?!Y)/g,
        months: /M(?!M)/g,
        weeks: /W(?!W)/g,
        days: /D(?!D)/g,
        hours: /H(?!H)/g,
        minutes: /m(?!m)/g,
        seconds: /s(?!s)/g,
        milliseconds: /S(?!S)/g
    }
    var matchRegexps = {
        years: /Y/g,
        months: /M/g,
        weeks: /W/g,
        days: /D/g,
        hours: /H/g,
        minutes: /m/g,
        seconds: /s/g,
        milliseconds: /S/g
    }
    for (var r in replaceRegexps) {
        if (replaceRegexps[r].test(output)) {
            var as = 'as'+r.charAt(0).toUpperCase() + r.slice(1);
            var value = new String(Math.floor(moment.duration(milliseconds - totalMilliseconds)[as]()));
            var replacements = output.match(matchRegexps[r]).length - value.length;
            output = output.replace(replaceRegexps[r], value);

            while (replacements > 0 && replaceRegexps[r].test(output)) {
                output = output.replace(replaceRegexps[r], '0');
                replacements--;
            }
            output = output.replace(matchRegexps[r], '');

            var temp = {};
            temp[r] = value;
            totalMilliseconds += moment.duration(temp).asMilliseconds();
        }
    }
    return output;
}

Features of this code:

d=moment.duration({hours:1,minutes:1,seconds:1});
d.format('HHH:mm:ss');
"001:01:01"
  • if you omit a character in your input template, and the value of the subsequent character is larger than it's usual maximum, it adds the previous to it, eg:
d=moment.duration({days:1, hours:1, minutes: 1});
d.format('H:mm:ss');
"25:01:00"

Possible problems:

  • uses Math.floor on values obtained from asXxxx, eg:
Math.floor(moment.duration(milliseconds)).asHours()
  • this will mean that if there is for example, values for minutes or seconds in the duration, but you ask the format function for hours, then it won't round up, it will always round down.

+1 for this request

Personally I think it makes more sense to implement .format() method than having some fancy rules for .humanize() or to create a .countdown() method. 95% of the issues can be solved with .format().

I agree that .humanize() should offer more precision but it should be a different feature.

Formatting duration is a must have. It should be easy to translate seconds in formated string.

I try the stralytic code but:
d =moment.duration({days:1, hours:1, minutes: 1}); d.format('D H:mm:ss');
"1 -215:01:00"

+1 for format()

As a usecase, Durations used in timing exams (3 hours) can be formatted easily as hh:mm(:ss) or so, which would be so, so much more easier. Right now, it is quite tough to do the same in Moment until I dabble in vanilla js :)

+1 duration format!

here's the quick fix I used:

moment.duration.fn.format = function(){
    str = ""
    if(this.days() > 1) str = str + Math.floor(this.days()) + "d "
    if(this.hours() > 1) str = str + Math.floor(this.hours()) + "h "
    if(this.minutes() > 1) str = str + Math.floor(this.minutes()) + "m "
    if(this.seconds() > 1) str = str + Math.floor(this.seconds()) + "s "
    return str
    }

:+1: for duration.format()

:+1: for duration.format() too

What is the status of this PR? Is it far off?

Code Bounty

I've been away for a while... Almost a year that I created this issue. I'll give it a try. I'll fork moment js and update this issue as soon as I have something to test/review. I have to prepare myself for an exam in two days. So it's unlikely that something will show within two days. That said, I'll be working on it.

@llacroix Thanks :)

:+1: for duration.format()

moment.duration.fn.format = function (zeros, twoDigit) {
    var hours = this.hours(), minutes = this.minutes(), seconds = this.seconds();
    var displayFormat = '', zerosFormat = twoDigit ? '00' : '0', padLeft = twoDigit ? -2 : -1;
    if (hours || zeros) {
        displayFormat += (zerosFormat + hours).slice(padLeft) + 'h ';
    }
    if (minutes || zeros) {
        displayFormat += (zerosFormat + minutes).slice(padLeft) + 'min ';
    }
    if (seconds || zeros) {
        displayFormat += (zerosFormat + seconds).slice(padLeft) + 's';
    }
    return $.trim(displayFormat);
}

+1 duration format.

+1 duration.format

+1 duration.format

I really needed comprehensive duration formatting, so I reviewed the threads here and on StackOverflow and sat down today to implement it.

I'm still working through a couple minor details, but the core is done and solid. I'll get the code and spec and examples posted here in the next few days. The basic idea is that you can have any arbitrary duration and format it with a string similar to the moment date format strings, eg. duration.format("d[d] hh:mm:ss") --> 2d 03:47:24

You can also define arbitrary decimal precision on the final value, eg. duration.format("h [hrs]", 3) --> 42.384 hrs

+1 for duration.format

I've posted my moment.duration.format plugin:
https://github.com/jsmreese/moment-duration-format

Test cases and a few examples are in the project.
My plugin is dependent on lodash and underscore.string.

+1 duration.format()

This ticket has been opened over a year ago now. I doubt it will ever be implemented.

@Maxwell2022 I posted a moment.duration.format plugin a week or so ago:
https://github.com/jsmreese/moment-duration-format

Will that work for you?

+1 to this as well. Seems like a very noticeable omission in an otherwise comprehensive library.

https://github.com/rmm5t/jquery-timeago might be a good template for how we can implement this in Moment...

@schmod I posted a moment.duration.format plugin last month:
https://github.com/jsmreese/moment-duration-format

Does that work for your use cases?

:+1: !

This would work for me (but wouldn't for > 24h durations) :

moment.duration.fn.format = function(format) {
  return moment(this.as('milliseconds')).format(format);
}

@jsmreese your https://github.com/jsmreese/moment-duration-format being dependent on LoDash is a real showstopper. We already use underscore, and I can't justify a switch to LoDash just for this little feature. If your plugin was independent of both that would make it a more viable option for a lot of people I think.

@wleeper Absolutely agree.

My environment happens to use LoDash and Underscore.String, so I used methods from those libraries -- I needed my first version a couple months ago and just wanted to get it implemented and out there.

I'll get those dependencies removed shortly.

@wleeper Underscore and LoDash are meant to be intercompatible. As long as @jsmreese isn't using anything not in the Underscore build of LoDash, you should be able to use his plugin as-is without any trouble.

@chall8908 That's the thing, and @wleeper is right -- I _am_ using features of LoDash that are not part of the Underscore build.

I've removed the Underscore.String dependency, and I'm working on the Underscore compatibility.

Although the moment-duration-format plugin solves one of these problems, I think that we need an approach that works across locales (which is, admittedly, a whole lot more difficult).

I think that we need to work on implementing #1241, which would open a lot of doors in terms of rendering human-readable dates relative dates, durations, and lists across locales. formatDuration would be fairly trivial to implement if Moment had access to the CLDR language data.

jQuery's Globalize library is working on tackling many of the same issues, and it seems logical to collaborate with them. Twitter also already has a very comprehensive library that does a lot of this sort of thing...

OK, here's an implementable API on top of CLDR. What do you think?

duration:human(bool) // future/past dep/indep
duration:human({
  with(=min+max): 'hours'|'minutes'|'seconds',
  min: 'hours',
  max: 'days',
  float: bool,
  length: "long|short|narrow",
  abs: bool
})
  • min: what is the minimum unit to use. min: days, means don't say hours, minutes, seconds, but round to days if duration is shorter than a day
  • max: what is the maximum unit to use. max: days, means not to use months and years, but instead the respective number of days
  • length: size of tokens: day vs d for English
  • abs: future/past independent

:+1: +1

:+1:

+1 duration.format

+1 duration.format

+1

+1

+1

Would like this to display the runtime of something.

+1

https://github.com/jsmreese/moment-duration-format

moment-duration-format version 1.2.1 is published on NPM.
It is functional in both Node.js and the Browser.
It does depend on Lo-Dash or Underscore, but is now tested and functional with both.
The original Underscore.String dependency has been removed.

I will publish this version to Bower just as soon as the current Bower package register/unregister issues are resolved.

+1 for duration format

Would love for this to become a part of the library.

+1

+1

+1

:+1:

+1 for duration.format()

+1

Oh yes I'd definitely be in, at least to be able to do moment.duration(3, 'seconds').get('ss') to output with leading zero values.

What is the state of this request? What help is needed to make progress on it?

@oncletom
This exists: https://github.com/jsmreese/moment-duration-format/
And can do what you want, if you don't mind the dependency on Lo-Dash or Underscore.
Someday soon I'll make some time to remove that dependency...

was surprised that https://github.com/jsmreese/moment-duration-format/ isn't in stdlib when humanize is. I feel that violates principle of least surprise. At the very least, getting back to a simple numeric format should be possible:

moment.duration(123, "minutes").format();
// "2:03:00"

For now I am using:

moment.utc(moment.duration(300 * 1000).asMilliseconds()).format("HH:mm:ss.SSS")
// 00:05:00.000

Would love to see this soon as a part of moments.js

+1

+1

On a related note, duration.toString() returns [Object object]. Shouldn't it return humanize()?

+1 would love to have more control over this.

+1

Just published Moment Duration Format 1.3.0, which removes the previous dependency on Lo-Dash or Underscore. Now the only dependency is Moment.js itself.

https://github.com/jsmreese/moment-duration-format/

@jsmreese Nice man! :beers:

@jsmreese cool. !
Why hasn't this been part of moment.js itself, I don't get it. humanize is not so useful without precision, why would I want to round 1h and 30minutes to 1 hour?.. No use case for that.

+1, the plugin by jsmreese works brilliantly but would be nice if it was part of moment.js.

+1. This feature should be in and humanize out.

+1 for duration.format

@jsmreese published his plugin close to a year ago, and this issue was opened two years ago. @timrwood @ichernev Can we please get this into the main moment.js library?

+1

+1

:+1: for duration.format

+1

:+1:

+1

What is the current status of this?

Maybe the maintainer is waiting till we reach 1000, or the New Years Eve? @icambron

@gkatsanos - I'm no longer active in helping maintaining Moment (and I was always just a helper), but my recommendation is a well-tested pull request. Surely there is someone requesting this willing to actually code it.

@icambron this exists already as a plugin.. what's there more to do?
who's the maintainer btw?

@icambron can you please point to the plugin?

and it seems to be a very well shaped plugin. except the fact it depends on lodash instead of underscore, are there any other things that prevent to make it as PR.. seems to be the port from lodash to underscore should not be that difficult. /cc @jsmreese

@alexanderbeletsky @gkatsanos Actually I removed the lodash or underscore dependency a while ago.

One of the major hurdles for my plugin being included in Moment.js core is the lack of full i18n support.

And that's a major concern for me, personally. The multiple languages supported are a big thing for me, and I'd hate to get into a situation where Feature A works in any language, but Feature B is English-only.

@jsmreese maybe if create some well defined tasks in your repository, of what exactly need to be done - I would definitely jump in to help.

@mattgrande @alexanderbeletsky The format tokens are already customizable, and the format template is arbitrary, so that's not an issue.

The default format templates are not localized in any way, and you can't localize the decimal point or add any sort of localized number formatting on values. That's all that's missing off the top of my head.

:+1:

+1 duration.format!

sooo....wat's the deal with this?

Just dropping in to note a few things, since there are like a million comments here. I'm not the maintainer and am no longer active in this project, but I'm pretty sure of two things:

  1. Everyone, you can just use @jsmreese's plugin. It looks great! Plugins are good things! (@jsmreese, if you're so inclined, you can add it to the list of Moment plugins in the documentation with a PR here: https://github.com/moment/momentjs.com)
  2. It's not going to be included in Moment's core until someone a) internationalizes it, b) integrates the tests into Moment's tests, and c) submits a PR. It will definitely not happen until someone does that.

+1 duration.format

+1 duration.format!

+1 duration.format

+1 duration.format. Our case is that we want to provide a function where one can pass an amount of seconds and a string that would format them. Right now we're doing it with moment.startof("w").add("s", nrOfSeconds).format( customFormatString );

Unfortunately just last week this produced an error since startof("w") is Sunday and on Sunday it was time for daylight saving time, so we were missing an hour there. Of course we can check that with isDSTShifted() but it would still be awesome to not have to convert a duration to a date just to format it.

+1 duration.format

+1 duration.format

+1 for duration.format

+1 for duration.format

Can we close this as apparently nobody +1ing actually reads this thread?

On Wed, Jun 10, 2015, 08:30 SamFromDaUk [email protected] wrote:

+1 for duration.format


Reply to this email directly or view it on GitHub
https://github.com/moment/moment/issues/463#issuecomment-110751635.

OR, fix it?

George, I think those who are adding +1 s are implicitly disagreeing, and
simply want these features.

If the notifications are irritating you, consider unsubscribing from this
thread.
On 11 Jun 2015 00:07, "George Katsanos" [email protected] wrote:

OR, fix it?


Reply to this email directly or view it on GitHub
https://github.com/moment/moment/issues/463#issuecomment-110767322.

The entire reason github doesn't have a vote feature (from my understanding) is because it discourages discussion.

You can implicitly disagree all you want, that's not helpful. If you disagree that's great, read through the thread and give your arguments (specifically, any new arguments or any points you think have been poorly considered).

I'm still subscribed because I _do_ think there's some interesting arguments left to be made, I look forward to hearing them, but the team shouldn't bow to mere peer pressure.

I can confirm the plugin @icambron mentioned above works.

If you're like me, you want a .fromNow() with broader output (like amazon's shipping countdown). Here's how to do that:

// include the plugin
var cutoffDate = moment().add(3, 'hours'); // some date in the future that we're counting down to
var now = moment();
var output = moment.duration(cutoffDate.diff(now)).format('h [hours] m [minutes] s [seconds]');
// "3 hours 0 minutes 0 seconds"

yep, I shall also make it clear - moment.duration().format() works with this plugin: https://github.com/jsmreese/moment-duration-format

if you're using meteor, go for oaf:moment-duration-format

This doesn't seem to be working for me, I'm using moment .diff between two times, which does work, the problem is when It is between "pm" and "am", say I'm traveling at 9pm and landing 2am, I should get the correct amount of time.

@Markj89 you need to open a stackoverflow topic.

+1

+1

+1

:+1:

+1 on closing this issue. using the plugin is a solid solution.

+1

+1

+1 on .format()

+1, still not implemented after 4 years? :D

+1

Btw. I think it should be possible to parse the humanized format as well. E.g. it is not that hard to parse 7 days and 5 hours...

Just wanted to emphasize @jsmreese's plugin worked great!

:+1:

+1 duration.format

+1 duration format

+1 duration.format

+1 duration.format

:+1:

I'm going to close this in favor of #1048. It doesn't mean it's gone, we just had two issues that are several years old and both boil down to 'make duration formatting'. The other one explains this more clearly.

+1 duration.format

+1 duration.format

+1

Use .localeData().relativeTime(45, true, 'mm') and get 45 minutes, and so on ;)

+1 Really so much talk about this and yet it's not implemented. There is even separate package for this https://github.com/jsmreese/moment-duration-format

to display duration in any format, simply convert duration to ms and then to moment:
moment(duration.as('milliseconds')).format('HH:mm:ss')

Thanks! Is this in the docs? I didn't see it...

This is not in the docs because it doesn't work. It is a hack using the unix epoch to interpret milliseconds as a point in time since the epoch. Thus, it falls apart if your duration is 24 hours or greater.

A few things about this code:

  1. An hh token is a token meant to be used with AM/PM, so your duration will only go up to 12

  2. Even if you use an HH token, which will go up to 23, your duration cannot be any longer than 23:59:59.999, as things will cross over into the next date

  3. As this code is written, it will only work on a server that is in UTC. Any browser in a different timezone will yield unexpected results.

If you want to use this hack it should be written as:

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

But as I pointed out, this will only work if your duration is under 24 hours. Over that, back to square 1.

Thanks. It took me a while today to figure out that one can concatenate .minutes() with .seconds(). Call me stupid, but it wasn't obvious for me from the docs what the difference between .seconds() and .asSeconds() is right away... But now I see it's actually there! :)

for example: console.log(duration.minutes()+":"+duration.seconds());

I'll stick with this method.

@elasticsteve You'll probably also want to add a leading zero to the seconds portion if it's less than ten. :wink:

@butterflyhug @elasticsteve that's actually the main reason why i wanted to use format. in my case it's a simple short time counter so @maggiepint's solution is enough for my needs.
moment.utc(duration.asMilliseconds()).format('HH:mm:ss')

@sagivo good point! Now the @maggiepint solution looks more appealing. My server is UTC anyway.

Sure, I totally get it. I've also used that hack in production code. But I wouldn't recommend it as a general solution (apart from a few specific use cases), because there are lots of situations where it fails badly. (E.g. negative durations are another important failure case that hasn't been explicitly mentioned yet.)

+1

+1 duration.format() !!!!!!!!!

+1

+1

+1

+1

+1

+1

+1

+1

+1

+1

+1

+1

+1

+1 hard to debug durations

+1

You can easily do something like:

    var duration = moment().add(5, 'days') -  moment().local();
    var s = Math.floor( (duration/1000) % 60 );
    var m = Math.floor( (duration/1000/60) % 60 );
    var h = Math.floor( (duration/(1000*60*60)) % 24 );
    var d = Math.floor( duration/(1000*60*60*24) );
    return d + ' days ' + h + ' hours ' + m + ' minutes ' + s  + ' seconds before the deadline.';   
    // 4 days 23 hours 59 minutes 59 seconds before the deadline.

Request one user twitter @Toon_Ladyboy

You can easily do something like:

    var duration = moment().add(5, 'days') -  moment().local();
    var s = Math.floor( (duration/1000) % 60 );
    var m = Math.floor( (duration/1000/60) % 60 );
    var h = Math.floor( (duration/(1000*60*60)) % 24 );
    var d = Math.floor( duration/(1000*60*60*24) );
    return d + ' days ' + h + ' hours ' + m + ' minutes ' + s  + ' seconds before the deadline.';   
    // 4 days 23 hours 59 minutes 59 seconds before the deadline.

Uggly, but effective.

2019, still in need of this feature.

A simple parameter in humanize, .e.g humanize(precise: true) , which would circumvent all the rounding would be enough to make everyone happy. Besides, rounding is the hard part to implement. The rest is just simple converting a duration like any other formatting done with format().

There is a great moment method called fromNow() that will return the time from a specific time in nice human readable form, like this:

moment('2019-04-30T07:30:53.000Z').fromNow() // an hour ago || a day ago || 10 days ago

Or if you want that between two specific dates you can use:

var a = moment([2007, 0, 28]);
var b = moment([2007, 0, 29]);
a.from(b); // "a day ago"

Taken from the Docs:

Can this be reopened? This is very basic functionality.

In my case I found a package which solved my problems:
https://github.com/EvanHahn/HumanizeDuration.js

Maybe it is useful for someone else as well. :)

July 2019 and this feature still not available.

July 2019 and this feature still not available.

Haven't tried it yet, but I just noticed this!
npm install moment-duration-format

https://github.com/jsmreese/moment-duration-format

September 2019 still officially miss this feature

d.format('H:mm:ss');
"1:01:01"

Also wish that it could have this feature

d.format('D-H:mm:ss'); // existence of D will mod hours to 24
"999-23:59:59"

In case anyone was wondering why this was closed: https://github.com/moment/moment/issues/463#issuecomment-228543000

This is by no means ideal, but I ended up doing something like this as a workaround. I had a duration object with a countdown for logging the user out after inactivity, and wanted to format the time remaining.

// What I did:
private getTimeString(duration: moment.Duration): string {
    const time = moment()
      .seconds(duration.seconds())
      .minutes(duration.minutes());

    return time.format('mm:ss');
}

// What I'd rather do (as many others have mentioned)...
private getTimeString(duration: moment.Duration): string {
    return duration.format('mm:ss');
}

A hacky solution of mine:

import moment from 'moment';

const formatInt = (int: number): string => {
  if (int < 10) {
    return `0${int}`;
  }
  return `${int}`;
};

export const formatDuration = (time: string): string => {
  const seconds = moment.duration(time).seconds();
  const minutes = moment.duration(time).minutes();
  const hours = moment.duration(time).hours();
  if (hours > 0) {
    return `${formatInt(hours)}:${formatInt(minutes)}:${formatInt(seconds)}`;
  }
  if (minutes > 0) {
    return `${formatInt(minutes)}:${formatInt(seconds)}`;
  }
  return `00:${formatInt(seconds)}`;
};

2020

I use the following method, it may be useful to someone else :)

function formatDuration(duration, format) {
  const date = moment().startOf('day');
  return date.add(duration).format(format);
}

(I use only to format durations between 00:00 and 23:59)

Still need this

These 'get' helps to format in way u want:

  duration.get('years')
  duration.get('months')
  duration.get('days')
  duration.get('hours')
  duration.get('minutes')
  duration.get('seconds')

What I work with:

const formatDuration = ms => {
  const days = Math.floor(ms / 8.64e7);
  const msOnLastDay = ms - days * 8.64e7;
  return (days < 10 ? "0" + days : days) + ":" + moment.utc(msOnLastDay).format("HH:mm:ss.SSS");
};
formatDuration(5)
"00:00:00:00.005"
formatDuration(500)
"00:00:00:00.500"
formatDuration(50000)
"00:00:00:50.000"
formatDuration(5000000)
"00:01:23:20.000"
formatDuration(500000000)
"05:18:53:20.000"
// for reference
JSON.stringify(moment.duration(500000000)._data, null, 2)
"{
  "milliseconds": 0,
  "seconds": 20,
  "minutes": 53,
  "hours": 18,
  "days": 5,
  "months": 0,
  "years": 0
}"

July 2019 and this feature still not available.

Haven't tried it yet, but I just noticed this!
npm install moment-duration-format

https://github.com/jsmreese/moment-duration-format

This works perfectly fine :)

The game is over :)

Thanks, appreciate that!!!


De: Aleksey Makas notifications@github.com
Enviado: sexta-feira, 9 de outubro de 2020 11:03
Para: moment/moment moment@noreply.github.com
Cc: Douglas Aguiar douglaszanquetta@hotmail.com; Comment comment@noreply.github.com
Assunto: Re: [moment/moment] Duration missing features (#463)

The game is over :)


You are receiving this because you commented.
Reply to this email directly, view it on GitHubhttps://github.com/moment/moment/issues/463#issuecomment-706200427, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AGD22DRNGNIQMOJFQY7VW3DSJ4J4VANCNFSM4ABRUZLA.

Was this page helpful?
5 / 5 - 1 ratings