Skip to content

Fix timestamps with years before 100 being parsed as 19xx/20xx - #1185

Open
spokodev wants to merge 1 commit into
porsager:masterfrom
spokodev:fix/date-year-before-100
Open

Fix timestamps with years before 100 being parsed as 19xx/20xx#1185
spokodev wants to merge 1 commit into
porsager:masterfrom
spokodev:fix/date-year-before-100

Conversation

@spokodev

@spokodev spokodev commented Aug 4, 2026

Copy link
Copy Markdown

Problem

The date / timestamp / timestamptz parser is parse: x => new Date(x), which hands PostgreSQL's text output straight to JavaScript's Date. For a year below 100, PostgreSQL's text (e.g. 0050-06-15 12:30:00+00) is not strict ISO 8601 (space separator, two-digit offset), so new Date falls back to its legacy parser, which maps the year into the 1900s or returns garbage:

const sql = postgres()
;(await sql`select '0050-06-15 12:30:00+00'::timestamptz as x`)[0].x  // 1950-06-15  (should be 0050)
;(await sql`select '0099-06-15 12:30:00+00'::timestamptz as x`)[0].x  // 1999-06-15  (should be 0099)
;(await sql`select '0001-06-15 12:30:00+00'::timestamptz as x`)[0].x  // 2015-01-06  (garbage)
;(await sql`select '0023-06-15 12:30:00+00'::timestamptz as x`)[0].x  // Invalid Date

Any timestamp with a year of 1 to 99 is silently corrupted (off by ~1900 years, or Invalid Date).

Fix

Normalize the text to ISO 8601 before new Date: replace the date/time space with T, and expand a two-digit timezone offset +HH to +HH:00. The ISO parser then handles years below 100 correctly. Years 100 and above, and plain date values, produce byte-identical output to before.

Verified against PostgreSQL 17 that the parsed values now match the pg driver for years 1 through 2020 across date, timestamp, and timestamptz, and that years >= 100 are unchanged.

Test

Added Date before year 100 to tests/index.js. It fails before the change and passes after.

The date and timestamp parser passed PostgreSQL's text output straight to
new Date(x). For a year below 100 such as '0050-06-15 12:30:00+00',
JavaScript's legacy date parser maps the year into the 1900s (or returns
Invalid Date), so the value was silently off by about 1900 years.

Normalize the text to ISO 8601 (space to T, two-digit timezone offset to
+HH:00) so the ISO parser is used, which handles years below 100
correctly. Years 100 and above are unaffected.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant