Skip to content

Commit

Permalink
fix: prevent timezone conversion for non-sensitive date value (#146)
Browse files Browse the repository at this point in the history
  • Loading branch information
johanohly authored Nov 18, 2024
1 parent 937bbf7 commit 092ea35
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 2 deletions.
22 changes: 22 additions & 0 deletions src/lib/utils/datetime/parse.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down Expand Up @@ -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'),
Expand Down
23 changes: 21 additions & 2 deletions src/lib/utils/datetime/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand All @@ -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) },
Expand Down Expand Up @@ -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) {
Expand Down

0 comments on commit 092ea35

Please sign in to comment.