From 11e454c0fdd2da8cc6b5821b89c03c52a7c64b91 Mon Sep 17 00:00:00 2001 From: Isaac Cambron Date: Tue, 22 Aug 2023 16:28:17 -0400 Subject: [PATCH] Fix for negative units in conversions Closes #1482 --- src/duration.js | 7 ++++--- src/impl/util.js | 4 ++++ test/duration/units.test.js | 9 +++++++++ 3 files changed, 17 insertions(+), 3 deletions(-) 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() //-------