diff --git a/cypress/test/functions/dates/format-date.cy.ts b/cypress/test/functions/dates/format-date.cy.ts new file mode 100644 index 0000000..bb1080c --- /dev/null +++ b/cypress/test/functions/dates/format-date.cy.ts @@ -0,0 +1,114 @@ +/** + * Please refer to the terms of the license agreement in the root of the project + * + * (c) 2025 Feedzai + */ +import { formatDate } from "../../../../src/functions"; + +const DEFAULT_LOCALES = { locales: "en-US" }; + +describe("formatDate", () => { + it("should format date string correctly", () => { + expect(formatDate({ date: "2024-01-15", ...DEFAULT_LOCALES })).to.equal( + "January 15" + ); + expect(formatDate({ date: "2024-12-31", ...DEFAULT_LOCALES })).to.equal( + "December 31" + ); + }); + + it("should format Date object correctly", () => { + const dateObject = new Date("2024-01-15"); + + expect(formatDate({ date: dateObject, ...DEFAULT_LOCALES })).to.equal( + "January 15" + ); + }); + + it("should format timestamp correctly", () => { + const timestamp = new Date("2024-01-15").getTime(); + + expect(formatDate({ date: timestamp, ...DEFAULT_LOCALES })).to.equal( + "January 15" + ); + }); + + it("should handle different date string formats", () => { + expect(formatDate({ date: "2024/01/15", ...DEFAULT_LOCALES })).to.equal( + "January 15" + ); + expect(formatDate({ date: "01-15-2024", ...DEFAULT_LOCALES })).to.equal( + "January 15" + ); + expect(formatDate({ date: "15 Jan 2024", ...DEFAULT_LOCALES })).to.equal( + "January 15" + ); + }); + + it("should include year when specified", () => { + const customOptions = { year: "numeric" } as const; + + expect( + formatDate({ + date: "2024-01-15", + options: customOptions, + ...DEFAULT_LOCALES, + }) + ).to.equal("January 15, 2024"); + }); + + it("should show short month format", () => { + const customOptions = { month: "short" } as const; + + expect( + formatDate({ + date: "2024-01-15", + options: customOptions, + ...DEFAULT_LOCALES, + }) + ).to.equal("Jan 15"); + }); + + it("should include weekday", () => { + const customOptions = { weekday: "long" } as const; + + expect( + formatDate({ + date: "2024-01-15", + options: customOptions, + ...DEFAULT_LOCALES, + }) + ).to.equal("Monday, January 15"); + }); + + it("should respect all provided options while maintaining defaults", () => { + const customOptions = { + weekday: "long", + year: "numeric", + month: "long", + day: "numeric", + } as const; + + expect( + formatDate({ + date: "2024-01-15", + options: customOptions, + ...DEFAULT_LOCALES, + }) + ).to.equal("Monday, January 15, 2024"); + }); + + it("should handle invalid dates", () => { + expect(() => formatDate({ date: "invalid-date" })).throw(); + expect(() => formatDate({ date: "2024-13-45" })).throw(); + }); + + it("should handle empty input", () => { + expect(() => formatDate({ date: "" })).throw(); + }); + + it("should handle null and undefined", () => { + expect(() => formatDate({ date: null })).throw(); + expect(() => formatDate()).throw(); + }); +}); diff --git a/docs/docs/functions/dates/format-date.mdx b/docs/docs/functions/dates/format-date.mdx new file mode 100644 index 0000000..5a2d369 --- /dev/null +++ b/docs/docs/functions/dates/format-date.mdx @@ -0,0 +1,27 @@ +--- +title: formatDate +--- + +Formats a date value into a localized string representation using the `toLocaleDateString()` method. + +### API + +```typescript +interface IFormatDateConfig { + date: ConstructorParameters<typeof Date>[0]; + locales?: Intl.LocalesArgument; + options?: Intl.DateTimeFormatOptions; +} + +function formatDate(config: IFormatDateConfig): string; +``` + +### Usage + +```typescript +import { formatDate } from "@feedzai/js-utilities"; + +const formattedDate = formatDate({ date: "2023-12-25" }); + +console.log(formattedDate); // "December 25" +``` diff --git a/src/functions/dates/format-date.ts b/src/functions/dates/format-date.ts new file mode 100644 index 0000000..220afc2 --- /dev/null +++ b/src/functions/dates/format-date.ts @@ -0,0 +1,43 @@ +/** + * Please refer to the terms of the license agreement in the root of the project + * + * (c) 2025 Feedzai + */ + +interface IFormatDateConfig { + date: ConstructorParameters<typeof Date>[0]; + locales?: Intl.LocalesArgument; + options?: Intl.DateTimeFormatOptions; +} + +const DEFAULT_OPTIONS = { + month: "long", + day: "numeric", +} as const; + +/** + * Formats a date value into a localized string representation. + * + * @param {IFormatDateConfig} config - Configuration object for date formatting. + * @returns {string} A localized date string. By default, returns the date in "{Month} {Day}" format (e.g., "December 25") + * + * @example + * formatDate({ date: "2023-12-25" }) + * // => "December 25" + */ +export const formatDate = ({ + date: dateValue, + locales, + options, +}: IFormatDateConfig) => { + const date = new Date(dateValue); + + if (!dateValue || isNaN(date.getTime())) { + throw new Error("Invalid date value"); + } + + return date.toLocaleDateString(locales, { + ...DEFAULT_OPTIONS, + ...options, + }); +}; diff --git a/src/functions/dates/index.ts b/src/functions/dates/index.ts index f539f53..ebede9e 100644 --- a/src/functions/dates/index.ts +++ b/src/functions/dates/index.ts @@ -4,3 +4,4 @@ * (c) 2024 Feedzai */ export * from "./get-browser-timezone"; +export * from "./format-date";