Skip to content

fix(export): write infinite timestamps and dates as infinity, not year 9999 - #339

Merged
Shman4ik merged 1 commit into
mainfrom
fix/export-infinity
Oct 1, 2026
Merged

Shman4ik merged 1 commit into
mainfrom
fix/export-infinity

Conversation

@Shman4ik

@Shman4ik Shman4ik commented Oct 1, 2026 •

Copy link
Copy Markdown
Owner

What and why

Npgsql reads a Postgres infinity / -infinity timestamp, timestamptz or date as the largest or smallest DateTime (also DateOnly, DateTimeOffset). Export and copy wrote those with "O", so CSV, TSV, Markdown, JSON and INSERT output had 9999-12-31T23:59:59.9999999 and 0001-01-01T00:00:00.0000000. Postgres reads both back as finite values. Since #330, range bounds use the same formatter, so [2026-01-01,infinity) had the same problem. The grid already showed infinity.

Fix:

  • New helper: PgValueSyntax.TemporalInfinity maps those max/min values to the words. It is the only code that knows Npgsql's mapping.
  • Export and copy: ResultExporter's scalar text calls the helper first. This covers cells, array elements and range bounds in every format. JSON now writes dates and times through the same text and no longer has its own "O" cases.
  • Grid: CellText.Temporal calls the same helper instead of keeping its own copy.
  • FK hop: its seed goes through FormatSqlLiteral, so it gets the fix too.

Known edge: Npgsql also reads 0001-01-01 00:00:00 as DateTime.MinValue. So the grid and export both show that one finite value as -infinity. This is documented in .claude/CLAUDE.md.

Not in this PR: filter-by-cell (RowFilterSql.ValueText), SqlLiteral.Format and PgValueSyntax.InvariantText have the same bug. A separate session is fixing them.

Visible to users (release notes)

Export and copy (CSV, TSV, JSON, Markdown, INSERT) now write infinite timestamps and dates as infinity / -infinity. Before, they wrote 9999-12-31T23:59:59.9999999 / 0001-01-01T00:00:00.0000000. Range bounds change the same way ([2026-01-01,infinity)).

Verified

  • dotnet build PgNimbus.slnx: 0 warnings, 0 errors

  • dotnet test --project tests/PgNimbus.Core.Tests:

    • Without a database: 2081 total, 0 failed, 111 skipped.
    • Live Postgres 17: all 66 ResultExporter* tests pass. That includes the 12 new live cases: scalar, array, range and multirange infinities, each written as TSV, INSERT and JSON and cast back on the server.
  • Every new test failed before the fix: 7/7 unit tests, and 12/12 live cases on the server.

  • dotnet test --project tests/PgNimbus.App.Tests: 760 total, 0 failed.

  • NativeAOT publish: not run. No new reflection or JSON serialization.

  • Screenshots: no scenario shows an infinite date, so no baseline or published image changes.

  • CI (build-test, postgres:17 with PGNIMBUS_TEST_CONN set): Core 2081 total, 0 failed, 13 skipped. The skips are SSH, the native keychain and preloaded pg_stat_statements; none of the new live cases skipped.

Anything left unverified: the full Core suite against a local server. Docker's engine crashed during the local run, so all of its database tests timed out.

Checklist

  • CLAUDE.md updated: the paragraph "Dates and times in the grid are ISO"
  • PgNimbus.Core still has zero UI dependencies

🤖 Generated with Claude Code

…r 9999

Npgsql reads a Postgres 'infinity' or '-infinity' timestamp, timestamptz or
date as the largest or smallest DateTime (DateOnly, DateTimeOffset). Export
and copy wrote those with "O", so every CSV/TSV/Markdown/JSON/INSERT carried
9999-12-31T23:59:59.9999999 and 0001-01-01T00:00:00.0000000, which Postgres
reads back as finite values. Range bounds went through the same formatter.

PgValueSyntax.TemporalInfinity is now the one place that knows the mapping;
ResultExporter's scalar text and CellText.Temporal both ask it first, so a
cell, an array element and a range bound ([2026-01-01,infinity)) all write
the word. The FK hop's seed goes through FormatSqlLiteral and gets it too.

ResultExporterInfinityTests covers every format; with PGNIMBUS_TEST_CONN it
reads 12 infinite values from the server and casts each written form back.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Shman4ik
Shman4ik merged commit 92266a5 into main Oct 1, 2026
2 checks passed
@Shman4ik
Shman4ik deleted the fix/export-infinity branch October 1, 2026 10:24
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