New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

duration formatting #1048

Open
mj1856 opened this Issue Sep 4, 2013 · 116 comments

Comments

Projects
None yet
@mj1856
Member

mj1856 commented Sep 4, 2013

We've touched on this before in #463 and #879 but never really talked about it directly in its own issue.

We need a method for formatting durations similar to how we format dates. It should be as simple as:

moment.duration(x).format("H:mm:ss")

Note that the formatting tokens would have to carry slightly different meaning, since we're representing an elapsed duration of time, rather than a time-of-day. I suggest the following:

  • hh would mean "hours remainder after accounting for days"
  • h would be the single digit form of hh
  • HH would mean "total whole hours"
  • H would be the single digit form of HH
  • HHH would mean "total hours including decimals" - although that can currently be done with duration.asHours(), so this might not be necessary.

Similar formatting would apply for other units. In this context, the highest unit would be a "day", which would be a standard day consisting of 24 standard hours. It wouldn't make sense to measure years or months with this due to calendaring issues.

Note, this came up recently (again) on StackOverflow in this question. The user was looking for something like duration.format("H:mm:ss"). This is the workaround:

Math.floor(duration.asHours()) + moment.utc(duration.asMilliseconds()).format(":mm:ss")

This works, but it feels hacky. This should be built in.

@sbruchmann

This comment has been minimized.

sbruchmann commented Sep 4, 2013

+1

@leo-mck

This comment has been minimized.

leo-mck commented Sep 5, 2013

moment.duration(x).format("H:mm:ss") was exactly what I was expecting, before understanding that it would not work. The workaround suggested by Matt worked fine but comparing with the elegance of other things in momentjs it sure seems hacky.

@robinvdvleuten

This comment has been minimized.

robinvdvleuten commented Sep 7, 2013

Isn't it better to do

moment.utc(total.asMilliseconds()).format("HH:mm:ss");

instead of

Math.floor(duration.asHours()) + moment.utc(duration.asMilliseconds()).format(":mm:ss")
@ghost

This comment has been minimized.

ghost commented Sep 7, 2013

Code Bounty

@mj1856

This comment has been minimized.

Member

mj1856 commented Sep 8, 2013

@robinvdvleuten - The problem with using the HH in the current formatter is that it represents the hour portion of a full date and time. When dealing with an elapsed time, there could well be 24 hours or more. Try passing 24 hours in, and you'll see that it gets reset to zero.

@robinvdvleuten

This comment has been minimized.

robinvdvleuten commented Sep 11, 2013

I noticed it indeed. I'm now using the calculated milliseconds to format it, but it's still a hacky workaround.

@icambron

This comment has been minimized.

Member

icambron commented Sep 16, 2013

Are you thinking there will just be one "level" of remaindering possible--e.g. no way to say "hours after accounting for months"? I think that's a perfectly reasonable limitation, but just to spitball a sec, I could imagine providing an "anchor" argument, like so:

moment.duration(x).format("hh:mm:ss", "M");

Which tells us that the hours should be modulo the month. The anchor is optional and would default to the largest unit plus one size up (in this case, days). Similarly, it could use the string itself to determine that the minutes are modulo the hours and seconds modulo minutes. Whereas if you did this:

moment.duration(x).format("hh:ss");

...the seconds would be modulo the hours.

That's probably all not a great idea--it's not ironed out (where to weeks go in this hierarchy?) and it's probably unnecessary (people are unlikely to want holes like that). But fun to think about.

@icambron

This comment has been minimized.

Member

icambron commented Sep 16, 2013

On a more serious note, how are you going to deal with month vs minutes with this lowercase/uppercase notation?

@mj1856

This comment has been minimized.

Member

mj1856 commented Sep 16, 2013

I was envisioning that days would be the maximum unit size, so months wouldn't enter the picture. Basically, this is the inverse of how we parse durations coming from asp.net time spans.

@icambron

This comment has been minimized.

Member

icambron commented Sep 16, 2013

Makes sense.

@lfnavess

This comment has been minimized.

lfnavess commented Oct 31, 2013

I have been reading a SCORM 2004 RTE (p77) document, and i found that for time interval representation is as follows, i think this came from a standar,

in theory i can pass a value like: P34H
and the parsers should interpret that as 1day and 10 Hours

i hope it could be posible to format the ouput with this in mind
like 'PHM'
and the formatter interpret that as total Hours remaining minutes?
i would like to be able to format the output like HH:MM

i hope this info is helpfull

timeinterval (second, 10,2):The timeinterval (second, 10, 2)denotes that the value for
the data model element timeinterval represents elapsed time with a precision of 0.01
seconds[1]. The SCORM dot-notation binding defines a particular format for a
characterstring to represent a timeinterval.
The format of the characterstring shall be as follows:
P[yY][mM][dD][T[hH][nM][s[.s]S]] where:
• y: The number of years (integer, >= 0, not restricted)
• m: The number of months (integer, >=0, not restricted)
• d: The number of days (integer, >=0, not restricted)
• h: The number of hours (integer, >=0, not restricted)
• n: The number of minutes (integer, >=0, not restricted)
• s: The number of seconds or fraction ofseconds (real or integer, >=0, not
restricted). If fractions of a second are used, SCORM further restricts the string to
a maximum of 2 digits (e.g., 34.45 – valid, 34.45454545 – not valid).
• The character literals designators P, Y, M, D, T, H, Mand Sshall appear if the
corresponding non-zero value is present.
• Zero-padding of the values shall be supported. Zero-padding does not change the
integer value of the number being represented by a set of characters. For
example, PT05H is equivalent to PT5H and PT000005H.
Example:
• P1Y3M2DT3H indicates a period of time of 1 year, 3 months, 2 days and 3 hours
• PT3H5M indicates a period of time of 3 hours and 5 minutes

Implementers should be aware that the format and binding is for the communication of
the data between a SCO and an LMS. Since the format is representing a period of time,
then a duration like PT5M is equivalent to PT300S.
If the data model element, that is of type timeinterval(second,10,2) contains a value, then
• The designator Pshall be present;
• If the value of years, months, days, hours, minutes or seconds is zero, the value
and corresponding character literal designation may be omitted, but at least one
character literal designator and value shall be present in addition to the designator
P;
• The designator Tshall be omitted if all of the time components (hours, minutes
and seconds) are not used. A zero value may be used with any of the time
components (e.g., PT0S).

@quietmint

This comment has been minimized.

quietmint commented Nov 26, 2013

Duration formatting would be an excellent addition. There's no need for two distinct "hour" tokens. Assume a duration of 32 hours. You'd never want to extract just 8 hours without also extracting 1 day.

I think @icambron has a good suggestion. Parse the format string into tokens and express the duration in terms of the largest unit. Parse the tokens one at a time in order (e.g., "DD:hh:ss" meaning number of complete days, number of complete hours after accounting for days, number of complete seconds after accounting for days + hours).

@jsmreese

This comment has been minimized.

jsmreese commented Dec 28, 2013

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

I think it addresses most of the ideas / use-cases in this thread.

@hotzenklotz

This comment has been minimized.

hotzenklotz commented Mar 13, 2014

@jsmreese Have you consider filing a pull request that contains your plugin as a core part of momentjs?

@jsmreese

This comment has been minimized.

jsmreese commented Mar 19, 2014

@hotzenklotz Yes I have considered filing a pull request.

I haven't done so because of all the reasons @icambron laid out in #1538.

My plugin:

  • depends on Lo-Dash
  • does not look and feel like Moment.js code
  • uses a completely different test setup

I would love for my plugin to become part of Moment.js core... but I'm not going to waste their time with a pull request before those issues are addressed.

@schmod

This comment has been minimized.

schmod commented Mar 19, 2014

We would also want to make sure that the code can be internationalized. Fortunately, most of the strings we would need are in the Unicode CLDR, so very little translation work should be necessary.

The CLDR also has locale-specific recommendations on how to format certain kinds of intervals, which could potentially be more useful than arbitrary duration formats. Not sure how that fits in here, but it may be nice to automagically be able to display locale-specific intervals between two specific times.

The CLDR also has information about how to display specific time intervals (rather than durations) which could be useful at some point...

English(US) Calendar Data

@jsmreese

This comment has been minimized.

jsmreese commented Jul 28, 2014

Just published a new version of Moment Duration Format that removes the previous dependency on Lo-Dash or Underscore.

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

@nathanhoel

This comment has been minimized.

nathanhoel commented Aug 14, 2014

@jsmreese Suits our needs perfectly. Thanks!

@outaTiME

This comment has been minimized.

outaTiME commented Dec 29, 2014

+1

5 similar comments
@mhayes14

This comment has been minimized.

mhayes14 commented Jan 13, 2015

+1

@rsweetland

This comment has been minimized.

rsweetland commented Feb 7, 2015

+1

@larssondaniel

This comment has been minimized.

larssondaniel commented Feb 7, 2015

+1

@mlegenhausen

This comment has been minimized.

Contributor

mlegenhausen commented Apr 29, 2015

+1

@oznu

This comment has been minimized.

oznu commented May 19, 2015

+1

@FrozenDroid

This comment has been minimized.

FrozenDroid commented Oct 11, 2017

The plugin works very well. Would love to see it merged into Moment.js. I can't see how durations are useful without it.

@luchillo17

This comment has been minimized.

luchillo17 commented Oct 11, 2017

It is a plugin because not all people uses duration, i don't see that much of an user base needing durations to justify making the code base bigger.

I'm even surprised the whole duration module isn't in a plugin.

@FrozenDroid

This comment has been minimized.

FrozenDroid commented Oct 11, 2017

Or that. Currently, the duration module is pointless to me. All the functions in it are just simple math that can be done just fine without a library.
If the plugin was merged, then I can see it having a good use.

@luchillo17

This comment has been minimized.

luchillo17 commented Oct 11, 2017

Maybe, but not thinking in that math is what libraries are good for, battle tested solutions so you and i don't have to waste time on such tasks, like for example i didn't know there were so many standards for duration, like ISO 8601, the durations module takes care of that for me so i don't need to know how that standard is defined.

@FrozenDroid

This comment has been minimized.

FrozenDroid commented Oct 11, 2017

I guess so.
Either way, I propose we reference the plugin in the documentation.
That way, people know the functionality is there, and don't have to take out to Google and search for this functionality.

@luchillo17

This comment has been minimized.

luchillo17 commented Oct 11, 2017

Indeed, took me some while to find out the plugin section for it.

@Invis1ble

This comment has been minimized.

Invis1ble commented Oct 11, 2017

4 years and still no reaction from owners... That's sad :(

@marwahaha

This comment has been minimized.

Member

marwahaha commented Oct 11, 2017

Hi folks,

This is something we're still working on. Moment is a volunteer community! We need to make sure a feature like this has these properties:

  1. works in every environment
  2. doesn't add too much bulk to the code
  3. doesn't re-invent the wheel (i.e. there's already a plugin to do this!)
  4. doesn't break existing features

It's possible this will merge at some point.
#3615

If you think the docs could better point to the duration formatting plugin (or other plugins!), please send a PR our way here: https://github.com/moment/momentjs.com/

@ownmaster

This comment has been minimized.

ownmaster commented Nov 17, 2017

@marwahaha

doesn't add too much bulk to the code
doesn't re-invent the wheel (i.e. there's already a plugin to do this!)

Well, since there is already duration-format plugin and duration inside moment library, maybe the best solution is to take out duration from moment.js into separate plugin and then implement all the "heavy" stuff inside that plugin?
By doing so 2 goals will be achieved:

  1. decrease moment.js size
  2. provide duration directly with the most useful features instead of very limited version.
@schmod

This comment has been minimized.

schmod commented Nov 17, 2017

One large challenge is that duration formatting will be very difficult to implement across the full range of locales that moment.js supports.

I'd hate to see those locales lose the limited duration support that they currently have, or for Moment to add a feature that only works correctly in some locales. Keeping duration formatting in a plugin seems like a good middle-ground that ensures that the "core" of moment.js is stable, and works for everyone, while giving single-locale users the option to use plugins that perform functions specific to their locale.

@OogieBoogieInJSON

This comment has been minimized.

OogieBoogieInJSON commented Nov 22, 2017

The duration formatting plugin already exists and is referenced inside the documentation. Thats more than enough.

@luchillo17

This comment has been minimized.

luchillo17 commented Nov 22, 2017

@OogieBoogieInJSON Well, the docs aren't that helpful, i basically had to check this issue before even getting to the plugins in the docs, there's little exposure to those features unless you actually try and read the whole docs, which admittedly nobody does.

@OogieBoogieInJSON

This comment has been minimized.

OogieBoogieInJSON commented Nov 23, 2017

@luchillo17 I do read all the docs before working with anything. Probably, thats just me.

@luchillo17

This comment has been minimized.

luchillo17 commented Nov 24, 2017

Haha, yeah, it's great that you do, everyone should, but most of us as devs have schedules to meet, so understanding every nut & bolt of all libs we use isn't practical.

@OogieBoogieInJSON

This comment has been minimized.

OogieBoogieInJSON commented Nov 24, 2017

@luchillo17 It's not the documentation's fault you do Management Oriented Programming. Cheers!

@jsmreese

This comment has been minimized.

jsmreese commented Dec 13, 2017

For those following the saga of formatting moment durations, I've published version 2.0.0 of my moment-duration-format plugin.

The new version resolves/incorporates almost all the issues and feedback from the past four years version 1 has been in the wild -- including localization and pluralizing support as well as some useful formatting options.

Check it out here: https://github.com/jsmreese/moment-duration-format/releases

@OogieBoogieInJSON

This comment has been minimized.

OogieBoogieInJSON commented Dec 14, 2017

The real MVP -> @jsmreese

@jsmreese

This comment has been minimized.

jsmreese commented Dec 15, 2017

Hah. Thanks for the kind words, @OogieBoogieInJSON.

I can't help but note that my plugin stands on top of -- and wouldn't exist without -- the huge efforts of moment's creators and maintainers, not to mention the many, many contributors. My taking the time now to revisit something I created four years ago (wow, has it really been that long!) quite frankly pales in comparison to their continuous shepherding of this project!

@jsmreese

This comment has been minimized.

jsmreese commented Dec 22, 2017

Aaaaaand version 2.1.0 is published.
https://github.com/jsmreese/moment-duration-format/releases

Updated version fixes a few issues from version 2.0, and introduces moment.duration.format, a new function for coordinated formatting of multiple durations. Not to be confused with the already-existing moment.duration.fn.format.

The new function takes an array of durations, and returns an array of formatted strings, and is useful whenever you have a group of durations that must be formatted together in a consistent manner.

moment.duration.format([
    moment.duration(1, "second"),
    moment.duration(1, "minute"),
    moment.duration(1, "hour")
], "d [days] hh:mm:ss");
// ["0:00:01", "0:01:00", "1:00:00"]

moment.duration.format([
    moment.duration(1, "minute"),
    moment.duration(1, "day")
], "w [weeks], d [days], h [hours], m [minutes], s [seconds]", { trim: "all" });
// ["0 days, 1 minute", "1 day, 0 minutes"]
@prusswan

This comment has been minimized.

prusswan commented Dec 22, 2017

@jsmreese 2.0 did lead to some errors earlier so I had to lock it to 1.3.0 for safety, nevertheless thank you for keeping the feature/project alive.

@jsmreese

This comment has been minimized.

jsmreese commented Dec 22, 2017

@prusswan please do give version 2.1.0 a try. I'd like to know if you still see those errors!

@jsmreese

This comment has been minimized.

jsmreese commented Jan 16, 2018

I've published version 2.2.0 of moment-duration-format, which now includes a fallback number format function because toLocaleString is not fully implemented in many environments.

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

I've tested the new version using BrowserStack on a range of Android devices with OS versions from 2.2 to 7, and on a range of iOS devices with OS versions from 4.3 to 11. Also tested on Chrome, Firefox, IE 8-11, and Edge browsers.

@prusswan and others who had to lock the version to 1.3.0, you'll likely find that version 2.2.0 is finally the drop-in replacement that version 2.0.0 was supposed to be.

Thank you to all who have logged issues against version 2 of this plugin!

@jsmreese

This comment has been minimized.

jsmreese commented Jan 17, 2018

Having implemented version 2 of the moment-duration-format plugin, there are some obvious improvements for a version 3.

I've listed my ideas below and added them as issues on the repository. If you have ideas or comments about what you'd like to see, please let me know!

Hopefully the next version will be published in something like 4 months... not the 4-year wait for version 2.

  • The fallback number formatting localization options should be included with the Moment Locale object extensions I've already made for localizing duration unit labels. This would put all of the localization configuration in one place.

  • moment-duration-format and its fallback number formatting function do not follow the same API as Number#toLocaleString for significant digits and faction digits. The fallback function should be updated to use the toLocaleString API, and the plugin should expose the toLocaleString API options directly rather than hiding some of the options and masking them behind precision and useSignificantDigits options.

  • Exposing the fallback number formatting function as well as the toLocaleString feature test function would facilitate testing and allow them to be used outside of the context of formatting durations.

  • Add type definitions to support TypeScript, publish NuGet package, and support whatever other packaging options are in use these days. (This doesn't have to wait until version 3.)

  • Testing of the plugin should be modernized, ideally to match the Moment.js testing setup. (This doesn't have to wait until version 3, either.)

@prusswan

This comment has been minimized.

prusswan commented Jan 17, 2018

@jsmreese Tremendous work, but totally don't feel pressured to bump the major version twice within a short period of time. If it is still in use after 4 years without an update, then it is probably mostly good enough. I feel this current issue can be closed since there is already a resolution (use the plugins). A new issue can be started to decide if this functionality should become part of moment itself.

@Boringboringstuff

This comment has been minimized.

Boringboringstuff commented Jan 19, 2018

@jsmreese Amazing. Thank you so much and just in time! Huge deal for me and thank you for all that you do.

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