Skip to content
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

feat: add rescale option to Duration.normalize method #1299

Merged
merged 6 commits into from
Oct 16, 2022

Conversation

NGPixel
Copy link
Contributor

@NGPixel NGPixel commented Oct 10, 2022

The Problem

There's a use case right now where you have a duration from a set of units but want them to be displayed to the user in a more "human readable" format.

For example, you might want to display the duration between various 2 datetimes, which can defer in hours or just a few seconds:

const dur = Interval.fromDateTimes(start, end).toDuration(['hours', 'minutes', 'seconds', 'milliseconds'])
console.log(dur.toHuman())

// example outputs:
// 4 hours, 0 minutes, 12 seconds and 0 milliseconds
// 0 hours, 0 minutes, 5 seconds and 0 milliseconds
// 0 hours, 54 minutes, 0 seconds and 0 milliseconds

Because the duration can vary greatly between just a few seconds and many hours, the current output is completely useless.
One would expect the normalize() method to solve this problem but unfortunately, the current implementation only adjust the units currently in use.

const dur = Duration.fromObject({ milliseconds: 90000 })
console.log(dur.normalize().toHuman())

// output: 90000 milliseconds

In this example, normalizing 90000 milliseconds will still get you... 90000 milliseconds. Not useful at all. Again, because the duration can vary greatly, using shiftTo() is not a viable option.

The Solution

This PR adds a rescale option to the normalize() method which also shifts units to their largest representation, on top of the current normalization. This basically remove any units with values of 0, giving you a clean output.

const dur = Interval.fromDateTimes(start, end).toDuration(['hours', 'minutes', 'seconds', 'milliseconds'])
console.log(dur.normalize({ rescale: true }).toHuman())

// example outputs:
// 4 hours and 12 seconds
// 5 seconds
// 54 minutes
const dur = Duration.fromObject({ milliseconds: 90000 })
console.log(dur.normalize({ rescale: true }).toHuman())

// output: 1 minute and 30 seconds

Notes

This could possibly be its own method (e.g. rescale()), but in my opinion, this is what you would expect the normalize() method to do. Therefore, I think it makes more sense to simply add an optional flag to the current normalize() method.

Thanks!

@linux-foundation-easycla
Copy link

linux-foundation-easycla bot commented Oct 10, 2022

CLA Signed

The committers listed above are authorized under a signed CLA.

@icambron
Copy link
Member

Ok, so this makes sense, but here are some changes I'd like. Essentially, I'd like to decompose this.

  1. Let's add removeZeros() as a top-level method. It just removes all the zeroed -.
  2. Let's add a shiftToAll() method defined as shiftTo("years", "months", "weeks", "days", "hours", "minutes", "seconds", "milliseconds")
  3. Let's not add other features to normalize but instead just add a new method called rescale(). Rescale is implemented as this.normalize().shiftToAll().removeZeros()

Does that make sense?

@NGPixel
Copy link
Contributor Author

NGPixel commented Oct 10, 2022

@icambron I refactored the code as requested.

@icambron icambron merged commit 7fe3eb0 into moment:master Oct 16, 2022
@icambron
Copy link
Member

Thanks! I'll release this soon

@NGPixel NGPixel deleted the rescale branch October 17, 2022 18:01
@NGPixel
Copy link
Contributor Author

NGPixel commented Oct 27, 2022

@icambron Any ETA for the next release?

@icambron
Copy link
Member

@NGPixel it's released now

@NGPixel
Copy link
Contributor Author

NGPixel commented Oct 31, 2022

Thanks!

@drc-gcoakley
Copy link

drc-gcoakley commented Jun 28, 2023

For the most part this looks great! It even handles negative numbers. Unfortunately, it does not handle zero.
Duration.fromObject({milliseconds: ms}).rescale().toHuman(); returns an empty string.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants