Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
13 changes: 8 additions & 5 deletions src/date.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,18 @@
* - 13-digit timestamps (Unix milliseconds) - used directly
* - String representations of timestamps
* - ISO date strings (e.g., "2025-06-01T12:30:00Z")
* - Simple date strings (e.g., "2025-06-01") - time defaults to 00:00:00
* - Simple date strings (e.g., "2025-06-01") - time defaults to 00:00:00 UTC
* - Date strings with space-separated time (e.g., "2025-06-01 12:30:00")
*
* Note: This function follows JavaScript Date constructor behavior for date parsing.
* Some invalid dates like "2025-02-30" auto-correct to valid dates (becomes "2025-03-02"),
* while malformed strings like "2025-13-01" or "2025-06-01T25:00:00" return null.
*
* For simple date strings without time components, the function uses UTC methods to ensure
* consistent behavior across all timezones, avoiding timezone shift bugs in date comparisons.
*
* @example
* coerceToDate('2025-06-01') // Returns Date object set to 2025-06-01 00:00:00
* coerceToDate('2025-06-01') // Returns Date object set to 2025-06-01 00:00:00 UTC
* coerceToDate('2025-06-01T12:30:00Z') // Returns Date object with specified time
* coerceToDate(1748834578) // Returns Date object (10-digit timestamp in seconds)
* coerceToDate(1748834578000) // Returns Date object (13-digit timestamp in milliseconds)
Expand Down Expand Up @@ -53,12 +56,12 @@ export const coerceToDate = (
// Return null for invalid dates
if (Number.isNaN(dateObj.getTime())) return null;

// If no time component is specified, set time to 00:00:00
// this is because by default JS will set the time to midnight UTC for that date
// If no time component is specified, set time to 00:00:00 UTC
// Use setUTCHours to avoid timezone shifts
const hasTimeComponent =
/T\d{2}:\d{2}(:\d{2})?/.test(dateInput) || /\d{2}:\d{2}/.test(dateInput);
if (!hasTimeComponent) {
dateObj.setHours(0, 0, 0, 0);
dateObj.setUTCHours(0, 0, 0, 0);
}

return dateObj;
Expand Down
10 changes: 5 additions & 5 deletions test/date.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,14 @@ describe('coerceToDate', () => {
});

describe('simple date string inputs', () => {
it('should handle simple date strings and set time to 00:00:00', () => {
it('should handle simple date strings and set time to 00:00:00 UTC', () => {
const dateString = '2025-06-01';
const result = coerceToDate(dateString);
expect(result).toBeInstanceOf(Date);
expect(result?.getHours()).toBe(0);
expect(result?.getMinutes()).toBe(0);
expect(result?.getSeconds()).toBe(0);
expect(result?.getMilliseconds()).toBe(0);
expect(result?.getUTCHours()).toBe(0);
expect(result?.getUTCMinutes()).toBe(0);
expect(result?.getUTCSeconds()).toBe(0);
expect(result?.getUTCMilliseconds()).toBe(0);
});

it('should handle date strings with slashes', () => {
Expand Down
Loading