Skip to content

Commit

Permalink
feat: add rescale option to Duration.normalize method (#1299)
Browse files Browse the repository at this point in the history
  • Loading branch information
NGPixel committed Oct 16, 2022
1 parent 07af510 commit 7fe3eb0
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 0 deletions.
41 changes: 41 additions & 0 deletions src/duration.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,17 @@ function normalizeValues(matrix, vals) {
}, null);
}

// Remove all properties with a value of 0 from an object
function removeZeroes(vals) {
const newVals = {};
for (const [key, value] of Object.entries(vals)) {
if (value !== 0) {
newVals[key] = value;
}
}
return newVals;
}

/**
* A Duration object represents a period of time, like "2 months" or "1 day, 1 hour". Conceptually, it's just a map of units to their quantities, accompanied by some additional configuration and methods for creating, parsing, interrogating, transforming, and formatting them. They can be used on their own or in conjunction with other Luxon types; for example, you can use {@link DateTime#plus} to add a Duration object to a DateTime, producing another DateTime.
*
Expand Down Expand Up @@ -701,6 +712,17 @@ export default class Duration {
return clone(this, { values: vals }, true);
}

/**
* Rescale units to its largest representation
* @example Duration.fromObject({ milliseconds: 90000 }).rescale().toObject() //=> { minutes: 1, seconds: 30 }
* @return {Duration}
*/
rescale() {
if (!this.isValid) return this;
const vals = removeZeroes(this.normalize().shiftToAll().toObject());
return clone(this, { values: vals }, true);
}

/**
* Convert this Duration into its representation in a different set of units.
* @example Duration.fromObject({ hours: 1, seconds: 30 }).shiftTo('minutes', 'milliseconds').toObject() //=> { minutes: 60, milliseconds: 30000 }
Expand Down Expand Up @@ -765,6 +787,25 @@ export default class Duration {
return clone(this, { values: built }, true).normalize();
}

/**
* Shift this Duration to all available units.
* Same as shiftTo("years", "months", "weeks", "days", "hours", "minutes", "seconds", "milliseconds")
* @return {Duration}
*/
shiftToAll() {
if (!this.isValid) return this;
return this.shiftTo(
"years",
"months",
"weeks",
"days",
"hours",
"minutes",
"seconds",
"milliseconds"
);
}

/**
* Return the negative of this Duration.
* @example Duration.fromObject({ hours: 1, seconds: 30 }).negate().toObject() //=> { hours: -1, seconds: -30 }
Expand Down
47 changes: 47 additions & 0 deletions test/duration/units.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,29 @@ test("Duration#shiftTo boils hours down to hours and minutes", () => {
});
});

//------
// #shiftToAll()
//-------
test("Duration#shiftToAll shifts to all available units", () => {
const dur = Duration.fromMillis(5760000).shiftToAll();
expect(dur.toObject()).toEqual({
years: 0,
months: 0,
weeks: 0,
days: 0,
hours: 1,
minutes: 36,
seconds: 0,
milliseconds: 0,
});
});

test("Duration#shiftToAll maintains invalidity", () => {
const dur = Duration.invalid("because").shiftToAll();
expect(dur.isValid).toBe(false);
expect(dur.invalidReason).toBe("because");
});

//------
// #normalize()
//-------
Expand Down Expand Up @@ -207,6 +230,30 @@ test("Duration#normalize can convert all unit pairs", () => {
}
});

//------
// #rescale()
//-------
test("Duration#rescale normalizes, shifts to all units and remove units with a value of 0", () => {
const sets = [
[{ milliseconds: 90000 }, { minutes: 1, seconds: 30 }],
[
{ minutes: 70, milliseconds: 12100 },
{ hours: 1, minutes: 10, seconds: 12, milliseconds: 100 },
],
[{ months: 2, days: -30 }, { months: 1 }],
];

sets.forEach(([from, to]) => {
expect(Duration.fromObject(from).rescale().toObject()).toEqual(to);
});
});

test("Duration#rescale maintains invalidity", () => {
const dur = Duration.invalid("because").rescale();
expect(dur.isValid).toBe(false);
expect(dur.invalidReason).toBe("because");
});

//------
// #as()
//-------
Expand Down

1 comment on commit 7fe3eb0

@bazuka5801
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@NGPixel Awesome work! Thanks! Waiting for the next version)

Please sign in to comment.