From 375dbb888d796080f0b15d91650d330a47d3e1f8 Mon Sep 17 00:00:00 2001 From: Arunendra21 <156455722+Arunendra21@users.noreply.github.com> Date: Tue, 4 Aug 2026 19:24:47 +0530 Subject: [PATCH] fix(utils): return original input from date formatters on invalid dates formatCompactTimestamp and formatAbsoluteDate both build their output from Date getters. An unparseable string produces an Invalid Date whose getters return NaN rather than throwing, so formatCompactTimestamp's try/catch fallback never ran and it returned "NaN-NaN NaN:NaN", while formatAbsoluteDate returned the literal "Invalid Date". Both now check Number.isNaN(date.getTime()) up front and fall back to the original input string, which is what the existing catch was meant to do. Valid dates are unaffected. Updates the formatCompactTimestamp invalid-date test to assert the returned value instead of only its type, and adds a matching test for formatAbsoluteDate. Co-authored-by: eeshsaxena --- packages/utils/src/formatting.test.ts | 9 +++++++-- packages/utils/src/formatting.ts | 10 ++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/packages/utils/src/formatting.test.ts b/packages/utils/src/formatting.test.ts index 6e8d43ce8fc..eb1a4108919 100644 --- a/packages/utils/src/formatting.test.ts +++ b/packages/utils/src/formatting.test.ts @@ -68,6 +68,10 @@ describe('formatAbsoluteDate', () => { expect(result).toMatch(/May/) expect(result).toMatch(/2023/) }) + + it('returns the original input for an unparseable date', () => { + expect(formatAbsoluteDate('not-a-date')).toBe('not-a-date') + }) }) describe('formatTime', () => { @@ -99,9 +103,10 @@ describe('formatCompactTimestamp', () => { expect(result).toMatch(/^\d{2}-\d{2} \d{2}:\d{2}$/) }) - it('returns a formatted string even for invalid dates (no throw)', () => { + it('returns the original input for invalid dates instead of a NaN string', () => { const result = formatCompactTimestamp('not-a-date') - expect(typeof result).toBe('string') + expect(result).toBe('not-a-date') + expect(result).not.toContain('NaN') }) }) diff --git a/packages/utils/src/formatting.ts b/packages/utils/src/formatting.ts index 3c26b464f2a..31faeb94fc7 100644 --- a/packages/utils/src/formatting.ts +++ b/packages/utils/src/formatting.ts @@ -104,6 +104,11 @@ export function formatDate(date: Date): string { */ export function formatAbsoluteDate(dateString: string): string { const date = new Date(dateString) + // An unparseable string yields an Invalid Date whose formatters return + // "Invalid Date"; fall back to the original input instead. + if (Number.isNaN(date.getTime())) { + return dateString + } return date.toLocaleDateString('en-US', { year: 'numeric', month: 'short', @@ -150,6 +155,11 @@ export function formatTimeWithSeconds(date: Date, includeTimezone = true): strin export function formatCompactTimestamp(iso: string): string { try { const d = new Date(iso) + // Invalid dates do not throw; their getters return NaN, so the catch + // below never fires. Guard explicitly and fall back to the input string. + if (Number.isNaN(d.getTime())) { + return iso + } const mm = String(d.getMonth() + 1).padStart(2, '0') const dd = String(d.getDate()).padStart(2, '0') const hh = String(d.getHours()).padStart(2, '0')