diff --git a/src/intervalToDuration/index.ts b/src/intervalToDuration/index.ts index 093843945e..dafdf5e3e9 100644 --- a/src/intervalToDuration/index.ts +++ b/src/intervalToDuration/index.ts @@ -8,6 +8,16 @@ import { differenceInYears } from "../differenceInYears/index.js"; import { toDate } from "../toDate/index.js"; import type { Duration, Interval } from "../types.js"; +type Options = { includeZeroValues?: boolean }; +type RequiredDuration = Pick< + Required, + "years" | "months" | "days" | "hours" | "minutes" | "seconds" +>; + +type NormalizedDuration = O extends { includeZeroValues: true } + ? RequiredDuration + : Duration; + /** * @name intervalToDuration * @category Common Helpers @@ -19,6 +29,7 @@ import type { Duration, Interval } from "../types.js"; * @typeParam DateType - The `Date` type, the function operates on. Gets inferred from passed arguments. Allows to use extensions like [`UTCDate`](https://github.com/date-fns/utc). * * @param interval - The interval to convert to duration + * @param options - The object with options * * @returns The duration object * @@ -28,15 +39,35 @@ import type { Duration, Interval } from "../types.js"; * start: new Date(1929, 0, 15, 12, 0, 0), * end: new Date(1968, 3, 4, 19, 5, 0) * }) + * // => { years: 39, months: 2, days: 20, hours: 7, minutes: 5 } + * + * @example + * // Get the duration with 0 values. + * intervalToDuration({ + * start: new Date(1929, 0, 15, 12, 0, 0), + * end: new Date(1968, 3, 4, 19, 5, 0) + * }, { includeZeroValues: true }) * // => { years: 39, months: 2, days: 20, hours: 7, minutes: 5, seconds: 0 } */ -export function intervalToDuration( +export function intervalToDuration( interval: Interval, -): Duration { + options?: O, +): NormalizedDuration { const start = toDate(interval.start); const end = toDate(interval.end); - const duration: Duration = {}; + const duration = ( + options?.includeZeroValues + ? ({ + years: 0, + months: 0, + days: 0, + hours: 0, + minutes: 0, + seconds: 0, + } satisfies RequiredDuration) + : {} + ) as NormalizedDuration; const years = differenceInYears(end, start); if (years) duration.years = years; diff --git a/src/intervalToDuration/test.ts b/src/intervalToDuration/test.ts index e7c8c4c48f..78a917bab9 100644 --- a/src/intervalToDuration/test.ts +++ b/src/intervalToDuration/test.ts @@ -70,6 +70,72 @@ describe("intervalToDuration", () => { expect(result).toEqual({}); }); + describe("includeZeroValues", () => { + it("return zero value as properties", () => { + const start = new Date(1929, 0, 15, 12, 0, 0); + const end = new Date(1968, 3, 4, 19, 5, 0); + const result = intervalToDuration( + { start, end }, + { includeZeroValues: true }, + ); + + expect(result).toEqual({ + years: 39, + months: 2, + days: 20, + hours: 7, + minutes: 5, + seconds: 0, + }); + }); + + it("returns zero values when the dates are the same", () => { + const start = new Date(2020, 2, 1, 12, 0, 0); + const end = new Date(2020, 2, 1, 12, 0, 0); + const result = intervalToDuration( + { start, end }, + { includeZeroValues: true }, + ); + + expect(result).toEqual({ + years: 0, + months: 0, + days: 0, + hours: 0, + minutes: 0, + seconds: 0, + }); + }); + + it("exclude zero value when 'includeZeroValues' is false", () => { + const start = new Date(1929, 0, 15, 12, 0, 0); + const end = new Date(1968, 3, 4, 19, 5, 0); + const result = intervalToDuration( + { start, end }, + { includeZeroValues: false }, + ); + + expect(result).toEqual({ + years: 39, + months: 2, + days: 20, + hours: 7, + minutes: 5, + }); + }); + + it("returns duration of 0 when 'includeZeroValues' is false and the dates are the same", () => { + const start = new Date(2020, 2, 1, 12, 0, 0); + const end = new Date(2020, 2, 1, 12, 0, 0); + const result = intervalToDuration( + { start, end }, + { includeZeroValues: false }, + ); + + expect(result).toEqual({}); + }); + }); + describe("edge cases", () => { it("returns correct duration for dates in the end of Feb - issue 2255", () => { expect(intervalToDuration({