Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions utils/format-date-time.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@

import { formatDateTime } from "./format-date-time";

describe("formatDateTime", () => {
// ===== solitary =====
// We isolate the function from the JS runtime's locale implementation by mocking toLocaleDateString.
// This ensures we are testing the logic of option passing and string manipulation, not the Intl API itself.

it("calls toLocaleDateString with time options when includeTime is true", () => {
const spy = jest.spyOn(Date.prototype, "toLocaleDateString").mockReturnValue("Sat, Mar 23, 12:00 PM");

const result = formatDateTime("2024-03-23T12:00:00", { includeTime: true });

expect(spy).toHaveBeenCalledWith("en-US", expect.objectContaining({
weekday: "short",
month: "short",
day: "numeric",
hour: "numeric",
minute: "2-digit",
hour12: true
}));
expect(result).toBe("Sat Mar 23 12:00 PM");
spy.mockRestore();
});

it("calls toLocaleDateString with year options when includeTime is false", () => {
const spy = jest.spyOn(Date.prototype, "toLocaleDateString").mockReturnValue("Sat, Mar 23, 2024");

const result = formatDateTime("2024-03-23T12:00:00", { includeTime: false });

expect(spy).toHaveBeenCalledWith("en-US", expect.objectContaining({
weekday: "short",
month: "short",
day: "numeric",
year: "numeric"
}));
expect(result).toBe("Sat Mar 23 2024");
spy.mockRestore();
});

// ===== sociable =====
// We use real Date and Intl objects to ensure the function works correctly with the actual JS runtime.
// We use date strings without timezone offsets to ensure deterministic results across different environments.

it("formats date and time by default (includeTime: true)", () => {
// Verify that a valid date string is formatted with weekday, month, day, and time
const date = "2024-03-23T12:00:00";
expect(formatDateTime(date)).toBe("Sat Mar 23 12:00 PM");
});

it("formats date and time when includeTime is explicitly true", () => {
// Verify that explicitly passing includeTime: true produces the same result as default
const date = "2024-03-23T12:00:00";
expect(formatDateTime(date, { includeTime: true })).toBe("Sat Mar 23 12:00 PM");
});

it("formats date and year when includeTime is false", () => {
// Verify that when includeTime is false, time is omitted and year is included
const date = "2024-03-23T12:00:00";
expect(formatDateTime(date, { includeTime: false })).toBe("Sat Mar 23 2024");
});

it("handles invalid date strings gracefully", () => {
// Verify that an invalid date string returns 'Invalid Date'
expect(formatDateTime("not-a-date")).toBe("Invalid Date");
});

it("handles empty date strings gracefully", () => {
// Verify that an empty date string returns 'Invalid Date'
expect(formatDateTime("")).toBe("Invalid Date");
});

it("handles null or undefined date strings", () => {
// Verify that null or undefined (cast to any) returns 'Invalid Date'
expect(formatDateTime(null as any)).toBe("Invalid Date");
expect(formatDateTime(undefined as any)).toBe("Invalid Date");
});
});
11 changes: 7 additions & 4 deletions utils/format-date-time.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,27 @@
* Format date string to readable format
*/
export function formatDateTime(dateString: string, options: { includeTime?: boolean } = { includeTime: true }): string {
if (!dateString) {
return "Invalid Date";
}
const date = new Date(dateString);

const formatOptions: Intl.DateTimeFormatOptions = {
weekday: "short", // "Sun"
month: "short", // "Mar"
day: "numeric", // "23"
};

if (options.includeTime) {
formatOptions.hour = "numeric"; // "4"
formatOptions.minute = "2-digit"; // "13"
formatOptions.hour12 = true; // PM/AM
} else {
formatOptions.year = "numeric"; // "2024"
}

return date
.toLocaleDateString("en-US", formatOptions)
.replace(",", "")
.replace(/,/g, "")
.replace(/\s+/g, " ");
}
Loading