Skip to content

Commit

Permalink
Fix normalize() to handle partially negative inputs (#1467)
Browse files Browse the repository at this point in the history
* fixed issue #1233

from 1b73593

* Update units.test.js
  • Loading branch information
thomassth committed Aug 9, 2023
1 parent dc26ed2 commit 2411f6e
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 11 deletions.
30 changes: 19 additions & 11 deletions src/duration.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,20 +126,19 @@ function clone(dur, alts, clear = false) {
return new Duration(conf);
}

function antiTrunc(n) {
return n < 0 ? Math.floor(n) : Math.ceil(n);
// this is needed since in some test cases it would return 0.9999999999999999 instead of 1
function removePrecisionIssue(a) {
return Math.trunc(a * 1e3) / 1e3;
}

// NB: mutates parameters
function convert(matrix, fromMap, fromUnit, toMap, toUnit) {
const conv = matrix[toUnit][fromUnit],
raw = fromMap[fromUnit] / conv,
sameSign = Math.sign(raw) === Math.sign(toMap[toUnit]),
// ok, so this is wild, but see the matrix in the tests
added =
!sameSign && toMap[toUnit] !== 0 && Math.abs(raw) <= 1 ? antiTrunc(raw) : Math.trunc(raw);
toMap[toUnit] += added;
fromMap[fromUnit] -= added * conv;
added = Math.floor(raw);

toMap[toUnit] = removePrecisionIssue(toMap[toUnit] + added);
fromMap[fromUnit] = removePrecisionIssue(fromMap[fromUnit] - added * conv);
}

// NB: mutates parameters
Expand Down Expand Up @@ -577,7 +576,13 @@ export default class Duration {
* @return {number}
*/
toMillis() {
return this.as("milliseconds");
let sum = this.values.milliseconds ?? 0;
for (let unit of reverseUnits.slice(1)) {
if (this.values?.[unit]) {
sum += this.values[unit] * this.matrix[unit]["milliseconds"];
}
}
return sum;
}

/**
Expand Down Expand Up @@ -694,8 +699,11 @@ export default class Duration {
normalize() {
if (!this.isValid) return this;
const vals = this.toObject();
normalizeValues(this.matrix, vals);
return clone(this, { values: vals }, true);
if (this.valueOf() >= 0) {
normalizeValues(this.matrix, vals);
return clone(this, { values: vals }, true);
}
return this.negate().normalize().negate();
}

/**
Expand Down
4 changes: 4 additions & 0 deletions test/duration/units.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,10 @@ test("Duration#normalize handles the full grid partially negative durations", ()
{ months: 0, days: -28 },
{ months: 0, days: -28 },
],
[
{ hours: 96, minutes: 0, seconds: -10 },
{ hours: 95, minutes: 59, seconds: 50 },
],
];

sets.forEach(([from, to]) => {
Expand Down

0 comments on commit 2411f6e

Please sign in to comment.