diff --git a/src/duration.js b/src/duration.js index 56cf194b1..76a57b276 100644 --- a/src/duration.js +++ b/src/duration.js @@ -10,6 +10,7 @@ import { isUndefined, normalizeObject, roundTo, + signedFloor, } from "./impl/util.js"; import Settings from "./settings.js"; import DateTime from "./datetime.js"; @@ -133,9 +134,9 @@ function removePrecisionIssue(a) { // NB: mutates parameters function convert(matrix, fromMap, fromUnit, toMap, toUnit) { - const conv = matrix[toUnit][fromUnit], - raw = fromMap[fromUnit] / conv, - added = Math.floor(raw); + const conv = matrix[toUnit][fromUnit]; + const raw = fromMap[fromUnit] / conv; + const added = signedFloor(raw); toMap[toUnit] = removePrecisionIssue(toMap[toUnit] + added); fromMap[fromUnit] = removePrecisionIssue(fromMap[fromUnit] - added * conv); diff --git a/src/impl/util.js b/src/impl/util.js index 51f756ea4..b934b1053 100644 --- a/src/impl/util.js +++ b/src/impl/util.js @@ -124,6 +124,10 @@ export function parseMillis(fraction) { } } +export function signedFloor(number) { + return number > 0 ? Math.floor(number) : Math.ceil(number); +} + export function roundTo(number, digits, towardZero = false) { const factor = 10 ** digits, rounder = towardZero ? Math.trunc : Math.round; diff --git a/test/duration/units.test.js b/test/duration/units.test.js index 2b37fad4f..42aaf2397 100644 --- a/test/duration/units.test.js +++ b/test/duration/units.test.js @@ -96,6 +96,15 @@ test("Duration#shiftTo boils hours down to hours and minutes", () => { }); }); +test("Duration#shiftTo handles mixed units", () => { + const dur = Duration.fromObject({ weeks: -1, days: 14 }); + expect(dur.shiftTo("years", "months", "weeks").toObject()).toEqual({ + years: 0, + months: 0, + weeks: 1, + }); +}); + //------ // #shiftToAll() //-------