Skip to content

pgtype: parse extended-range text timestamps - #2631

Closed
sueun-dev wants to merge 1 commit into
jackc:masterfrom
sueun-dev:fix-extended-range-text-timestamps
Closed

pgtype: parse extended-range text timestamps#2631
sueun-dev wants to merge 1 commit into
jackc:masterfrom
sueun-dev:fix-extended-range-text-timestamps

Conversation

@sueun-dev

Copy link
Copy Markdown
Contributor

PostgreSQL accepts timestamp and timestamptz values outside the range that pgx's current text scan path can parse directly with Go's 2006 year layout. The binary path already handles values at the high end of PostgreSQL's range, but text/simple-protocol values such as 10000-01-02 03:04:05.123456 fail before they can scan.

This keeps the existing time.Parse result for ordinary four-digit AD years. For extended years and BC text values, it normalizes the year to a leap/non-leap surrogate before parsing the date/time and zone fields, then restores the PostgreSQL year into Go's astronomical year numbering. The result is checked against PostgreSQL's timestamp bounds. The extended/BC timestamptz text path allows the one-year display spillover that a numeric offset can produce, preserves that numeric offset as a fixed offset, and checks the final instant after applying the offset.

Checked:

  • With only the new tests kept and the source fix stashed, go test ./pgtype -run 'TestTimestampCodecDecodeTextBigTime|TestTimestamptzCodecDecodeTextBigTime|TestTimestamptzCodecDecodeTextBigTimePreservesOffset|TestTimestampCodecDecodeTextInvalid|TestTimestamptzDecodeTextInvalid' -count=1 -v failed on the text paths (cannot parse "0-01-02 ..." as "-") and on invalid BC/range/offset cases that returned no error.
  • PostgreSQL 17 accepted 10000-01-02 03:04:05.123456, normalized 00000000000010000-01-02 03:04:05.123456, accepted the lower timestamp boundary 4714-11-24 00:00:00 BC, rejected 4714-11-23 23:59:59.999999 BC, accepted 4713-02-29 00:00:00 BC, rejected 4712-02-29 00:00:00 BC, rejected 294277-01-01 00:00:00, rejected +16 time zone displacement, rejected 294276-12-31 23:59:59.999999-14, and accepted 294276-12-31 23:59:59.999999+14.
  • PostgreSQL 17 also accepted offset-spillover timestamptz values such as 294277-01-01 00:00:00+14, 294277-01-01 15:58:59.999999+15:59, and 4714-11-23 10:00:00-14 BC; it rejected the adjacent out-of-range values 294277-01-01 15:59:00+15:59, 4714-11-23 09:59:59.999999-14 BC, and 4714-11-24 00:00:00+14 BC.
  • go test ./pgtype -run 'TestTimestampCodecDecodeTextBigTime|TestTimestamptzCodecDecodeTextBigTime|TestTimestamptzCodecDecodeTextBigTimePreservesOffset|TestTimestampCodecDecodeTextInvalid|TestTimestamptzDecodeTextInvalid' -count=1 -v
  • go test -race ./pgtype -run 'TestTimestampCodecDecodeTextBigTime|TestTimestamptzCodecDecodeTextBigTime|TestTimestamptzCodecDecodeTextBigTimePreservesOffset|TestTimestampCodecDecodeTextInvalid|TestTimestamptzDecodeTextInvalid' -count=3
  • PGX_TEST_DATABASE=... go test ./pgtype -count=1
  • TZ=UTC PGX_TEST_DATABASE=... go test ./... -count=1
  • go test ./... -run '^$' -count=1
  • go build ./...
  • git diff --check

go vet ./pgtype still reports pre-existing unkeyed pgxtest.ValueRoundTripTest literals in pgtype/int_test.go; the same vet output reproduces on clean origin/master.

@jackc

jackc commented Aug 18, 2026

Copy link
Copy Markdown
Owner

Thanks for the report. After a bit more investigation, I determined that the root problem is that the time package parsing simply doesn't match PostgreSQL exactly. Rather that add another workaround I added a new parser to exactly match PostgreSQL (e089fb5). That solves this problem and several other edge cases.

@jackc jackc closed this Aug 18, 2026
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.

2 participants