Skip to content

DateTimeOffset bounds and elements refuse offsets beyond ±14:00 that timestamptz reads #131

Closed

Description

@CaffeinatedCoder

DateTimeOffsetRange, its multirange and DateTimeOffsetSet refuse an offset beyond ±14:00, which timestamptz reads (PostgreSQL takes up to ±15:59). Loud (FormatException). InstantRange reads the same text. Measured on main (3ecfa10) against PostgreSQL 17.10:

DateTimeOffsetRange.Parse("[2026-01-01 10:00:00+15:00,)", null);  // FormatException
InstantRange.Parse("[2026-01-01 10:00:00+15:00,)", null);         // [2025-12-31T19:00:00Z,)
SELECT '[2026-01-01 10:00:00+15:00,)'::tstzrange, '[2026-01-01 10:00:00+15:59,)'::tstzrange;
-- ["2025-12-31 19:00:00+00",) | ["2025-12-31 18:01:00+00",)

Found by LiteralCorpusProbeTests (#123), family offset range, on DateTimeOffsetRange, RangeSet<DateTimeOffsetRange>, DateTimeOffsetSet and DateTimeOffsetSet<T>.

Authority. docs/serialization.md: the text is "the same text the server itself reads". The document already handles the analogous case — a ±HH:mm:ss offset DateTimeOffset cannot hold is read as "that instant at offset zero".

Cause. DateTimeOffset holds offsets up to ±14:00, and IsoTemporal parses with DateTimeOffset.TryParseExact.

Options. Read an offset beyond ±14:00 as the instant at offset zero, like the seconds offset; or document the refusal. Not breaking either way.

Activity

  1. added
    bugSomething isn't working
    found-by/oracleFound by the generated-oracle machinery (claims × API surfaces)
    area/literalsParse, TryParse and formatting
    package/coreAffects CodoMetis.ValueRanges
    severity/lowCosmetic, message or documentation-level difference
    on Oct 17, 2026
  2. added this to the 10.0.0 milestone on Oct 18, 2026
  3. CaffeinatedCoder commented on Oct 18, 2026

    @CaffeinatedCoder
    OwnerAuthor

    Scope note from the fix (PR to follow): the same ±14:00 limit applied to DateTime bounds and elements (IsoTemporal.OffsetLength), so DateTimeRange.Parse("[2026-01-01 10:00:00+15:00,)") threw as well, while timestamp reads it (and drops the offset). Fixed together: both now read up to ±15:59:59, which is PostgreSQL's limit on 16 and 18.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/literalsParse, TryParse and formattingbugSomething isn't workingfound-by/oracleFound by the generated-oracle machinery (claims × API surfaces)package/coreAffects CodoMetis.ValueRangesseverity/lowCosmetic, message or documentation-level difference

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions