From a9d7d0398d22ebd4bfc3812ca0134a97606d54d9 Mon Sep 17 00:00:00 2001 From: Creed Haymond Date: Thu, 27 Jul 2023 00:09:29 -0600 Subject: [PATCH] fix: sub-second precisions need to be rounded at the seconds field to avoid adding floats (#2377) --- src/plugin/duration/index.js | 3 ++- test/plugin/duration.test.js | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/plugin/duration/index.js b/src/plugin/duration/index.js index 70d49296c..e2060c344 100644 --- a/src/plugin/duration/index.js +++ b/src/plugin/duration/index.js @@ -139,7 +139,8 @@ class Duration { let seconds = this.$d.seconds || 0 if (this.$d.milliseconds) { - seconds += Math.round(this.$d.milliseconds) / 1000 + seconds += this.$d.milliseconds / 1000 + seconds = Math.round(seconds * 1000) / 1000 } const S = getNumberUnitFormat(seconds, 'S') diff --git a/test/plugin/duration.test.js b/test/plugin/duration.test.js index f2c44156d..3e726af91 100644 --- a/test/plugin/duration.test.js +++ b/test/plugin/duration.test.js @@ -77,6 +77,15 @@ describe('Creating', () => { expect(dayjs.duration(1000.5).toISOString()).toBe('PT1.001S') expect(dayjs.duration(-1000.5).toISOString()).toBe('-PT1S') }) + it('should handle floating point rounding errors', () => { + // An example of this is when adding 2 to 0.812 seconds, which is how + // the seconds component is calculated in .toISOString(). + // > 2 + 0.812 + // 2.8120000000000003 + expect(dayjs.duration(-2812).toISOString()).toBe('-PT2.812S') // was -PT2.8120000000000003S + expect(dayjs.duration(3121632.27382247).toISOString()).toBe('PT52M1.632S') // was PT52M1.6320000000000001S + expect(dayjs.duration(7647826.525774224).toISOString()).toBe('PT2H7M27.827S') // was PT2H7M27.826999999999998S + }) }) describe('Parse ISO string', () => {