Duration missing features #463

Closed
llacroix opened this Issue Oct 10, 2012 · 149 comments

Projects

None yet
@llacroix

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.

@bryannielsen

+1 on this request

@rockymeza
Contributor

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

@llacroix

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.

@sylvainpolletvillard

+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

@timrwood
Member

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?

@bryannielsen

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?

@seaneagan

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

@llacroix

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.

This was referenced Nov 16, 2012
@ejain
ejain commented Dec 10, 2012

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?

@timrwood
Member

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

@hsablonniere
Contributor

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.

@bryannielsen

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

@viettienn

This is definitely a needed feature for everyone.

@surjikal
surjikal commented Feb 2, 2013

Need this!

@icambron
Member
icambron commented Apr 8, 2013

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

@thiagog3

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

@stralytic

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.
@Maxwell2022

+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.

@mancausoft

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"

@kumarharsh

+1 for format()

@kumarharsh

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

@1updesign

+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
    }
@clayzermk1

👍 for duration.format()

@hahmed
hahmed commented Aug 28, 2013

👍 for duration.format() too

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

@ghost
ghost commented Sep 7, 2013

Code Bounty

@llacroix

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.

@kumarharsh

@llacroix Thanks :)

@kayz1
kayz1 commented Sep 30, 2013

👍 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);
}
@xiemeilong

+1 duration format.

@tijhaart
tijhaart commented Dec 2, 2013

+1 duration.format

@nmehlei
nmehlei commented Dec 2, 2013

+1 duration.format

@jsmreese
Contributor
jsmreese commented Dec 7, 2013

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

@rinatio
rinatio commented Dec 12, 2013

+1 for duration.format

@jsmreese
Contributor

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.

@algesten

+1 duration.format()

@Maxwell2022

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

@jsmreese
Contributor

@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?

@schmod
schmod commented Jan 3, 2014

+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...

@jsmreese
Contributor
jsmreese commented Jan 3, 2014

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

Does that work for your use cases?

@mgcrea
mgcrea commented Jan 15, 2014

👍 !

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

moment.duration.fn.format = function(format) {
  return moment(this.as('milliseconds')).format(format);
}
@wleeper
wleeper commented Jan 23, 2014

@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.

@jsmreese
Contributor

@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.

@chall8908
Contributor

@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.

@jsmreese
Contributor

@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.

@schmod
schmod commented Jan 24, 2014

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

@ichernev
Contributor

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
@mhayes14
mhayes14 commented Feb 3, 2014

👍 +1

@ChiperSoft

👍

@ysulyma
ysulyma commented Mar 24, 2014

+1 duration.format

@jclark360

+1 duration.format

@80leaves
80leaves commented Apr 7, 2014

+1

@dittodhole
Contributor

+1

@ashclarke

+1

Would like this to display the runtime of something.

@laugel
laugel commented Apr 19, 2014

+1

@jsmreese
Contributor

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.

@alexbeletsky

+1 for duration format

@mruzekw
mruzekw commented May 8, 2014

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

@Los83
Los83 commented May 13, 2014

+1

@jamesrom

+1

@holic
holic commented May 18, 2014

👍

@eagleeye

+1 for duration.format()

@mukama
mukama commented May 30, 2014

+1

@oncletom

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?

@jsmreese
Contributor

@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...

@xaviershay

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
@DaSchTour

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

@Tolsi
Tolsi commented Jul 1, 2014

+1

@sebastibe

+1

@cowwoc
cowwoc commented Jul 15, 2014

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

@veloper
veloper commented Jul 18, 2014

+1 would love to have more control over this.

@koba04
koba04 commented Jul 23, 2014

+1

@jsmreese
Contributor

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/

@clayzermk1

@jsmreese Nice man! 🍻

@gkatsanos

@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.

@martincarlin87

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

@redben
redben commented Oct 22, 2014

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

@bguiz
bguiz commented Nov 6, 2014

+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?

@gaving
gaving commented Nov 12, 2014

+1

@yoshdog
yoshdog commented Nov 26, 2014

👍 for duration.format

@julian-r

+1

@frontmesh

👍

@AlexArchive

+1

What is the current status of this?

@gkatsanos

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

@icambron
Member
icambron commented Dec 4, 2014

@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.

@gkatsanos

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

@alexbeletsky

@icambron can you please point to the plugin?

@alexbeletsky

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

@jsmreese
Contributor
jsmreese commented Dec 4, 2014

@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.

@mattgrande
Contributor

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.

@alexbeletsky

@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.

@jsmreese
Contributor
jsmreese commented Dec 4, 2014

@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.

@n1ghtmare

👍

@hdias2310

+1 duration.format!

@togakangaroo

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

@icambron
Member

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.
@crush83
crush83 commented Mar 19, 2015

+1 duration.format

@Iorg
Iorg commented Mar 23, 2015

+1 duration.format!

@humpedli

+1 duration.format

@LePhil
LePhil commented Apr 7, 2015

+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.

@CharlesOkwuagwu

+1 duration.format

@chuanxd
chuanxd commented May 28, 2015

+1 duration.format

@mxpv
mxpv commented Jun 2, 2015

+1 for duration.format

@SamFromDaUk

+1 for duration.format

@togakangaroo

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

On Wed, Jun 10, 2015, 08:30 SamFromDaUk notifications@github.com wrote:

+1 for duration.format


Reply to this email directly or view it on GitHub
#463 (comment).

@gkatsanos

OR, fix it?

@bguiz
bguiz commented Jun 10, 2015

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" notifications@github.com wrote:

OR, fix it?


Reply to this email directly or view it on GitHub
#463 (comment).

@togakangaroo

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.

@cmawhorter

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"
@KristerV

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

@Markj89
Markj89 commented Jun 18, 2015

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.

@KristerV

@Markj89 you need to open a stackoverflow topic.

@JobaDiniz

+1

@adaptabi

+1

@BlueHotDog

👍

@cmawhorter

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

@veksen veksen referenced this issue in vuejs/vue-requests Jan 20, 2016
Closed

Time ago #1

@zerocooljs

+1

@gen4sp
gen4sp commented Feb 24, 2016

+1

@remypar5

+1 on .format()

@inf3rno
inf3rno commented Mar 15, 2016

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

@Hugheth
Hugheth commented Mar 23, 2016

+1

@inf3rno
inf3rno commented Mar 23, 2016

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

@abepetrillo

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

@toobulkeh toobulkeh referenced this issue in stefanpenner/ember-moment Apr 11, 2016
Closed

Support for Moment Addons? #165

@sutkovoy

👍

@qieqing
qieqing commented May 13, 2016

+1 duration.format

@simplesmiler simplesmiler referenced this issue in egoist/vue-timeago May 19, 2016
Open

Add precision option #9

@prophe05

+1 duration format

@aboalwi
aboalwi commented Jun 13, 2016

+1 duration.format

@dangoosby

+1 duration.format

@Asido
Asido commented Jun 21, 2016

👍

@maggiepint
Member

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.

@maggiepint maggiepint closed this Jun 25, 2016
@wsain001

+1 duration.format

@xblox
xblox commented Sep 26, 2016

+1 duration.format

@ondrek
ondrek commented Oct 17, 2016

+1

@rawthriver

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

@vedmant
vedmant commented Dec 14, 2016

+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

@sagivo
sagivo commented Jan 3, 2017 edited

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

@elasticsteve

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

@maggiepint
Member

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.

@elasticsteve
elasticsteve commented Jan 4, 2017 edited

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.

@butterflyhug
Member

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

@sagivo
sagivo commented Jan 4, 2017 edited

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

@elasticsteve

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

@butterflyhug
Member

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

@qi-yu
qi-yu commented Mar 13, 2017

+1

@SlancikM

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment