diff --git a/src/lib/utils/datetime/parse.test.ts b/src/lib/utils/datetime/parse.test.ts index 6d30428..587e391 100644 --- a/src/lib/utils/datetime/parse.test.ts +++ b/src/lib/utils/datetime/parse.test.ts @@ -3,6 +3,8 @@ import { describe, it, expect } from 'vitest'; import { mergeTimeWithDate } from './parse'; +import { toUtc } from '$lib/utils/datetime/helpers'; + describe('mergeTimeWithDate', () => { it('should merge date and time correctly for 24-hour format', () => { const result = mergeTimeWithDate('2023-10-10', '9:30', 'America/New_York'); @@ -80,6 +82,26 @@ describe('mergeTimeWithDate', () => { expect(result.getMinutes()).toBe(0); }); + it('should merge date and time correctly for 18:59 in New York', () => { + const result = mergeTimeWithDate( + '2024-11-09T00:00:00.000Z', + '18:59', + 'America/New_York', + ); + expect(result).toBeInstanceOf(TZDate); + expect(result.getFullYear()).toBe(2024); + expect(result.getMonth() + 1).toBe(11); + expect(result.getDate()).toBe(9); + expect(result.getHours()).toBe(18); + expect(result.getMinutes()).toBe(59); + }); + + it('should throw an error for invalid date format', () => { + expect(() => + mergeTimeWithDate('10-10-2023', '10:30', 'America/New_York'), + ).toThrow('Invalid ISO 8601 date time string: 10-10-2023'); + }); + it('should throw an error for invalid time format', () => { expect(() => mergeTimeWithDate('2023-10-10', '25:00', 'America/New_York'), diff --git a/src/lib/utils/datetime/parse.ts b/src/lib/utils/datetime/parse.ts index 3857cf9..8482d02 100644 --- a/src/lib/utils/datetime/parse.ts +++ b/src/lib/utils/datetime/parse.ts @@ -21,7 +21,7 @@ export const mergeTimeWithDate = ( time: string, tzId: string, ): TZDate => { - const date = parseLocalISO(dateString, tzId); + const { year, month, day } = extractDateFromISO(dateString); const match = time.match(timePartsRegex); if (!match) { throw new Error('Invalid format'); @@ -44,7 +44,7 @@ export const mergeTimeWithDate = ( } const result = parse( - `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()} ${hours}:${minutes}`, + `${year}-${month}-${day} ${hours}:${minutes}`, 'yyyy-M-d H:m', new Date(), { in: tz(tzId) }, @@ -83,6 +83,25 @@ export const dateValueFromISO = (iso: string) => { ); }; +const ISO_DATE_REGEX = /(\d{4})-(\d{2})-(\d{2})/; +const extractDateFromISO = (iso: string) => { + const match = iso.match(ISO_DATE_REGEX); + if (!match) { + throw new Error('Invalid ISO 8601 date time string: ' + iso); + } + + const [, year, month, day] = match; + if (!year || !month || !day) { + throw new Error('Invalid ISO 8601 date time string: ' + iso); + } + + return { + year: parseNumber(year, 1, 9999), + month: parseNumber(month, 1, 12), + day: parseNumber(day, 1, 31), + }; +}; + function parseNumber(value: string, min: number, max: number) { const val = Number(value); if (val < min || val > max) {