From d37caedd64792abd8fb4026c3a6092880b83c9ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=AA=20Duy=20Quang?= Date: Mon, 30 Dec 2024 22:40:54 +0700 Subject: [PATCH] Make `applyDuration` reversible. --- src/duration.ts | 33 +++++++++++++++++++++++++++------ test/duration.ts | 19 +++++++++++-------- 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/src/duration.ts b/src/duration.ts index 74cb017..28c3bfe 100644 --- a/src/duration.ts +++ b/src/duration.ts @@ -84,14 +84,35 @@ export class Duration { } } +const durationApplicationActionsForward = [ + (r: Date, duration: Duration) => { + r.setUTCFullYear(r.getUTCFullYear() + duration.years) + }, + (r: Date, duration: Duration) => { + r.setUTCMonth(r.getUTCMonth() + duration.months) + }, + (r: Date, duration: Duration) => { + r.setUTCDate(r.getUTCDate() + duration.weeks * 7 + duration.days) + }, + (r: Date, duration: Duration) => { + r.setUTCHours(r.getUTCHours() + duration.hours) + }, + (r: Date, duration: Duration) => { + r.setUTCMinutes(r.getUTCMinutes() + duration.minutes) + }, + (r: Date, duration: Duration) => { + r.setUTCSeconds(r.getUTCSeconds() + duration.seconds) + }, +] +const durationApplicationActionsBackward = [...durationApplicationActionsForward].reverse() + export function applyDuration(date: Date | number, duration: Duration): Date { const r = new Date(date) - r.setFullYear(r.getFullYear() + duration.years) - r.setMonth(r.getMonth() + duration.months) - r.setDate(r.getDate() + duration.weeks * 7 + duration.days) - r.setHours(r.getHours() + duration.hours) - r.setMinutes(r.getMinutes() + duration.minutes) - r.setSeconds(r.getSeconds() + duration.seconds) + if (duration.sign < 0) { + for (const action of durationApplicationActionsBackward) action(r, duration) + } else { + for (const action of durationApplicationActionsForward) action(r, duration) + } return r } diff --git a/test/duration.ts b/test/duration.ts index 3b35600..ecb9e68 100644 --- a/test/duration.ts +++ b/test/duration.ts @@ -81,16 +81,19 @@ suite('duration', function () { }) suite('applyDuration', function () { - const referenceDate = '2022-10-21T16:48:44.104Z' const tests = new Set([ - {input: 'P4Y', expected: '2026-10-21T16:48:44.104Z'}, - {input: '-P4Y', expected: '2018-10-21T16:48:44.104Z'}, - {input: '-P3MT5M', expected: '2022-07-21T16:43:44.104Z'}, - {input: 'P1Y2M3DT4H5M6S', expected: '2023-12-24T20:53:50.104Z'}, - {input: 'P5W', expected: '2022-11-25T16:48:44.104Z'}, - {input: '-P5W', expected: '2022-09-16T16:48:44.104Z'}, + {referenceDate: '2022-10-21T16:48:44.104Z', input: 'P5W', expected: '2022-11-25T16:48:44.104Z'}, + {referenceDate: '2022-11-25T16:48:44.104Z', input: '-P5W', expected: '2022-10-21T16:48:44.104Z'}, + {referenceDate: '2022-07-21T16:43:44.104Z', input: 'P3MT5M', expected: '2022-10-21T16:48:44.104Z'}, + {referenceDate: '2022-10-21T16:48:44.104Z', input: '-P3MT5M', expected: '2022-07-21T16:43:44.104Z'}, + {referenceDate: '2022-10-21T16:48:44.104Z', input: 'P4Y', expected: '2026-10-21T16:48:44.104Z'}, + {referenceDate: '2026-10-21T16:48:44.104Z', input: '-P4Y', expected: '2022-10-21T16:48:44.104Z'}, + {referenceDate: '2022-10-21T16:48:44.104Z', input: 'P1Y2M3DT4H5M6S', expected: '2023-12-24T20:53:50.104Z'}, + {referenceDate: '2023-12-24T20:53:50.104Z', input: '-P1Y2M3DT4H5M6S', expected: '2022-10-21T16:48:44.104Z'}, + {referenceDate: '2023-08-15T00:00:00.000Z', input: 'P1Y3M25D', expected: '2024-12-10T00:00:00.000Z'}, + {referenceDate: '2024-12-10T00:00:00.000Z', input: '-P1Y3M25D', expected: '2023-08-15T00:00:00.000Z'}, ]) - for (const {input, expected} of tests) { + for (const {referenceDate, input, expected} of tests) { test(`${referenceDate} -> ${input} -> ${expected}`, () => { assert.equal(applyDuration(new Date(referenceDate), Duration.from(input))?.toISOString(), expected) })