From 02a44f3c97183c5335297af1aab4df42fe90801b Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Fri, 24 Apr 2026 13:57:31 +0000 Subject: [PATCH] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/lib/format.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/lib/format.ts b/src/lib/format.ts index 943d822..c5392a9 100644 --- a/src/lib/format.ts +++ b/src/lib/format.ts @@ -3,6 +3,24 @@ export function formatCurrency(amount: number | string | null | undefined) { return new Intl.NumberFormat("en-US", { style: "currency", currency: "USD" }).format(n || 0); } +/** + * Parse a date-only string ("YYYY-MM-DD") as a LOCAL date (midnight in the + * user's timezone). Using `new Date("2026-04-24")` parses as UTC midnight, + * which renders as the previous day in negative-offset timezones — that's + * the source of the "due date is one day earlier" bug. + * + * Returns null for falsy/invalid input. If a non date-only string or Date is + * passed, returns a Date built from it as-is. + */ +export function parseDateOnly(value: string | Date | null | undefined): Date | null { + if (!value) return null; + if (value instanceof Date) return value; + const m = value.match(/^(\d{4})-(\d{2})-(\d{2})$/); + if (m) return new Date(+m[1], +m[2] - 1, +m[3]); + const d = new Date(value); + return isNaN(d.getTime()) ? null : d; +} + export function formatDate(value: string | Date | null | undefined) { if (!value) return "—"; // Date-only strings ("YYYY-MM-DD") must be rendered in UTC, otherwise