diff --git a/CHANGELOG.md b/CHANGELOG.md index 52990f6..ff51720 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- `getQuarter` utility function +- `addQuarters` utility function + ## [2.3.0] - 2026-04-07 ### Added diff --git a/src/lib/date.spec.ts b/src/lib/date.spec.ts index 71a1393..b2336f1 100644 --- a/src/lib/date.spec.ts +++ b/src/lib/date.spec.ts @@ -10,6 +10,8 @@ import { getEndOfDay, getFirstDayOfYear, getLastDayOfYear, + addQuarters, + getQuarter, } from "./date"; describe("date tests", () => { @@ -162,4 +164,33 @@ describe("date tests", () => { expect(getLastDayOfYear(date).getTime()).toBe(new Date(2024, 11, 31, 0, 0, 0, 0).getTime()); } }); + + test.each([ + [null as unknown as Date, Number.NaN], + [undefined as unknown as Date, Number.NaN], + [42 as unknown as Date, Number.NaN], + ["test" as unknown as Date, Number.NaN], + [new Date("invalid-date"), Number.NaN], + [new Date("2026-01-15"), 1], + [new Date("2026-04-10"), 2], + [new Date("2026-08-20"), 3], + [new Date("2026-11-05"), 4], + ])("getQuarter", (date, expected) => { + expect(getQuarter(date)).toBe(expected); + }); + + test.each([ + [null as unknown as Date, 1, new Date(Number.NaN)], + [undefined as unknown as Date, -1, new Date(Number.NaN)], + [42 as unknown as Date, 1, new Date(Number.NaN)], + ["test" as unknown as Date, -1, new Date(Number.NaN)], + [new Date("invalid-date"), 1, new Date(Number.NaN)], + [new Date(Number.NaN), 1, new Date(Number.NaN)], + [new Date(2026, 4, 29), 1, new Date(2026, 7, 29)], + [new Date(2026, 4, 29), 4, new Date(2027, 4, 29)], + [new Date(2026, 8, 15), -1, new Date(2026, 5, 15)], + [new Date(2026, 8, 15), -4, new Date(2025, 8, 15)], + ])("addQuarters", (date, amount, expected) => { + expect(addQuarters(date, amount).getTime()).toBe(expected.getTime()); + }); }); diff --git a/src/lib/date.ts b/src/lib/date.ts index 8039339..b91f628 100644 --- a/src/lib/date.ts +++ b/src/lib/date.ts @@ -10,6 +10,8 @@ import { startOfDay, endOfDay, lastDayOfYear, + getQuarter as getQuarterInternal, + addQuarters as addQuartersInternal, } from "date-fns"; /** @@ -112,3 +114,22 @@ export function getFirstDayOfYear(date: Date): Date { export function getLastDayOfYear(date: Date): Date { return dateIsValid(date) ? lastDayOfYear(date) : new Date(Number.NaN); } + +/** + * Get the year quarter for the given date + * @param date The date + * @returns The year quarter + */ +export function getQuarter(date: Date): number { + return dateIsValid(date) ? getQuarterInternal(date) : Number.NaN; +} + +/** + * Shifts a date by a given number of quarters. + * @param date The date + * @param amount Number of quarters to shift by (negative values shift the date backwards) + * @returns A new Date shifted by the specified number of quarters + */ +export function addQuarters(date: Date, amount: number): Date { + return dateIsValid(date) ? addQuartersInternal(date, amount) : new Date(Number.NaN); +}