Skip to content

[Pg-kit]: Add Temporal support for PostgreSQL (rebase of #4475)#5656

Open
SamPearlma wants to merge 5 commits intodrizzle-team:mainfrom
SamPearlma:pr-4475
Open

[Pg-kit]: Add Temporal support for PostgreSQL (rebase of #4475)#5656
SamPearlma wants to merge 5 commits intodrizzle-team:mainfrom
SamPearlma:pr-4475

Conversation

@SamPearlma
Copy link
Copy Markdown

Summary

This PR is a continuation of #4475, originally opened by @XiNiHa. It adds Temporal mapping support for PostgreSQL date, time, timestamp, and interval columns via a new { mode: 'temporal' } option.

The original PR fell behind main and developed merge conflicts. Since I don't have permission to push to the contributor's fork, I rebased the branch onto the latest main, resolved the conflicts (primarily in pnpm-lock.yaml), and added the test coverage and scope adjustments described below so the work is ready to review and merge.


What changed relative to #4475

  • Rebased onto the latest main and resolved merge conflicts.

  • Added integration test coverage for the Temporal-mode variants of date, time, timestamp, and interval:

    • Round-trip validation
    • DST stability across session time zones
    • Calendar unit preservation
    • Error paths
  • Added a temporal-polyfill setup file wired into Vitest via setupFiles so the test suite runs on Node versions without native Temporal support.

  • Scope change for interval:

    • Removed the optional postgres-interval peer dependency
    • Removed fallback branch in PgTemporalInterval.mapFromDriverValue

See Known limitations below.

No other functional changes were introduced beyond conflict resolution.


Testing

Integration tests exercise the Temporal mode for every supported column type against a live Postgres:

  • date, time (with precision)
  • timestamp (with/without TZ, configurable precision)
  • interval

All column types co-exist in a single all-columns table to verify schema generation and mixed inserts.

Additional assertions:

  • Timestamps remain stable across DST transitions (spring-forward and fall-back) under session time zones:

    • UTC
    • America/New_York
    • Asia/Tokyo
  • Interval tests cover:

    • ISO 8601 round-trip
    • Preservation of months and years without requiring relativeTo
    • DrizzleError on unparseable driver values

Known limitations

interval Temporal mode requires:

intervalstyle = 'iso_8601'

on the session. The default PostgreSQL output styles (postgres, postgres_verbose, sql_standard) are not supported and will throw a DrizzleError with a clear remediation message.


Why the fallback was removed

The postgres-interval fallback was removed because it can silently produce incorrect durations for two real server outputs:

postgres_verbose

Example:

@ 2 days 3 hours 45 mins 30 secs

The tokenizer matches "mins" as a month prefix and produces:

  • months: 45
  • Loss of minutes
  • Fabricated year-month component

sql_standard

Example:

2 3:45:30

This drops the leading day count and returns:

  • { hours: 3, minutes: 45, seconds: 30 }
  • Off by two days

Because the result is still populated (not empty), the incorrect parse cannot be safely detected at runtime, risking silent data corruption. Failing loudly on unsupported formats is the safer contract.

This rationale is documented in PgTemporalInterval.mapFromDriverValue for future reference.


Temporal.Duration support notes

Supported inputs include ISO 8601-2 extensions supported by Temporal.Duration.from, such as:

  • Leading signs
  • Weeks combined with other units

Examples like:

  • P3W1D
  • -P1M

will round-trip correctly, even though strict ISO 8601-1 would reject them.

Note: other systems reading the same column may not accept these extended forms.


Original work

All implementation and design decisions are from the original author, @XiNiHa. Please refer to the original PR for full context and discussion: #4475.


Notes

  • Commit history has been preserved where possible (no squashing beyond what the rebase required).
  • This PR exists to unblock review and merging of the original contribution.

Related

XiNiHa and others added 5 commits April 16, 2026 13:22
The postgres-interval package silently returned wrong values for two
PostgreSQL interval styles rather than throwing:

  - postgres_verbose ("@ 2 days 3 hours 45 mins 30 secs") tokenized
    "mins" as a month prefix and produced months: 45, losing the
    minutes and fabricating a year-month component.
  - sql_standard ("2 3:45:30") dropped the leading day count and
    returned { hours: 3, minutes: 45, seconds: 30 }, off by two days.

Because the result was populated but wrong, the bad parse could not be
detected at runtime, risking silent data corruption for any caller on a
session configured with one of those styles.
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