`Duration#toHuman` does not print human-readable strings
See original GitHub issueBased on the name I would expect that Duration#toHuman
returns strings that are optimal for human reading. But, IMHO this is not the case.
The way I see it there are three issues.
- If a
Duration
is created from a number of milliseconds then the milliseconds are printed as-is, which is not human-readable.
Duration.fromMillis(22140000).toHuman() //=> "22140000 milliseconds"
In this case, I would expect something like the string “6 hours and 9 minutes” which is what humanize-duration returns.
- If a
Duration
is created with some units being zero then those units are printed even though they do not benefit humans.
Duration.fromMillis(3 * 60 * 1000).shiftTo("hours", "minutes").toHuman()
//=> "0 hours, 3 minutes"
Duration.fromObject({ days: 0, hours: 0, minutes: 12, seconds: 0 }).toHuman()
//=> "0 days, 0 hours, 12 minutes, 0 seconds"
- If a
Duration
is created with an empty object then an empty string is returned. An empty string is not a human-readable duration.
Duration.fromObject({}).toHuman() //=> ""
It seems to me that toHuman
only returns the internal representation of the duration with unit names attached and not actual human-friendly output.
I think that either the toHuman
method should be renamed as the current name is confusing or the above problems should be fixed. Units that are zero should not be printed and small units should be converted into larger units if possible. To fix the last issue I think that toHuman
should accept a (potentially optional) second argument that specifies the smallest unit to print. This argument can be used to not print unwanted precision (for instance milliseconds) and will be used as the fallback unit to print if the duration contains no units.
Here is a small proof of concept of what I suggest:
function toHuman(dur: Duration, smallestUnit = "seconds"): string {
const units = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds", ];
const smallestIdx = units.indexOf(smallestUnit);
const entries = Object.entries(
dur.shiftTo(...units).normalize().toObject()
).filter(([_unit, amount], idx) => amount > 0 && idx <= smallestIdx);
const dur2 = Duration.fromObject(
entries.length === 0 ? { [smallestUnit]: 0 } : Object.fromEntries(entries)
);
return dur2.toHuman();
}
For the above examples this implementation behaves as follows:
toHuman(Duration.fromMillis(3 * 60 * 1000)) //=> "3 minutes"
toHuman(Duration.fromObject({ days: 0, hours: 0, minutes: 12, seconds: 0 })) //=> "12 minutes"
toHuman(Duration.fromObject({})) //=> "0 seconds"
Issue Analytics
- State:
- Created 2 years ago
- Reactions:67
- Comments:27 (4 by maintainers)
Additional to your modified
toHuman()
method I’d like to go even further. In my opinion the.toHuman()
method should have the following behaviour, some examples:And I would like to see some new options for the
.toHuman()
method (with examples):Config Option:
stripZeroUnits
Removes all zero parts from the human-readable string. Allowed values are
all
which would remove all parts that are zero, orend
which would only remove zero parts at the end of the text. Examples:Config Option:
precision
Determines a minimum precision of the human-readable string. All parts of it which are smaller than the specified precision will be omitted. Examples:
Config Option:
maxUnits
An integer that determines the maximum allowed number of parts. Examples:
Config Options:
smallestUnit
andbiggestUnit
Determine the biggest and smallest unit that should be used. Default values are
smallestUnit: "seconds"
andbiggestUnit: "years"
. Examples:To achieve this behaviour I have written the following wrapper function for the
.toHuman()
method:According to the contribution guidelines one should ask first if Luxon wants to integrate this or that feature before putting too much effort into this … So here it is:
Do you think this feature set should be included into Luxon? If so, I could make a pull request if you want.
Hi there,
I’d just like to bump this issue. I would love to see some of the changes proposed by @orphic-lacuna and @paldepind, especially those focused on stripping 0 values and dealing with them within the
toHuman()
function. Specifically elegantly resolving the following:Duration.fromObject({ days: 0, hours: 0, minutes: 75 }).toHuman() // => 0 days, 1 hours, 15 minutes, 0 seconds
It looks like this is a relatively old PR/issue. Are there any updates or other info on this being implemented soon?