Repository navigation
Parse timestamps with Durations.ZonedTimestamp - #43
Draft
quinnj-bot[bot] wants to merge 2 commits into
Draft
quinnj-bot[bot] wants to merge 2 commits into
quinnj-bot[bot] wants to merge 2 commits into
Conversation
Durations.iso2timestamp reads ISO 8601 text with a UTC offset, checks
every field, and compiles under juliac --trim=safe, so the driver no
longer needs its own timestamp parser. Timestamp{P} fields call it
directly. DateTime fields read Timestamp{Millisecond} with RoundDown,
which handles both timestamp and timestamptz text and replaces the
offset sniffing in pg_parse_datetime_any and parse_timestamptz.
Errors keep their types. iso2timestamp reports precision and range
failures as ArgumentError, so on that path the driver parses again
with RoundDown to raise InexactError or PostgresInterfaceError as
before.
Requires Durations 1.5.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Durations dropped `iso2timestamp` in favor of making its existing parsers
compile under `juliac --trim=safe`. Read `timestamp` and `timestamptz` text
with `ZonedTimestamp{P,:UTC}` and a `DateFormat` for PostgreSQL's ISO
DateStyle. It reads the UTC offset when the text has one. Text with a `T`
between the date and the time, as JSON and `row_to_json` write it, reads
with `Durations.ISOTimestampFormat`, as the old parser accepted it too.
`DateTime` fields read through `Timestamp{Microsecond}`, and past its range
through `Timestamp{Millisecond}`, so PostgreSQL's last years still decode.
On a parse error, reading again at microseconds and then milliseconds tells
digits finer than the field's resolution (`InexactError`) from a time
outside its range (`PostgresInterfaceError`). Other text keeps the parser's
`ArgumentError`.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Postgres.jl should not keep its own timestamp parser. Dates and Durations already parse timestamps, and JuliaData/Durations.jl#10 makes them compile under
juliac --trim=safeand read PostgreSQL's UTC offsets. This PR moves the driver onto them and deletes its parser.It stays a draft until Durations releases that change.
[compat]asks for Durations 1.5, so CI cannot resolve packages before then.What changes
timestampandtimestamptztext.Durations.ZonedTimestamp{P,:UTC}(text, PG_TIMESTAMP_FORMAT)reads the local time with aDateFormatfor PostgreSQL's ISO DateStyle, then the UTC offset when the text has one. Text without an offset reads as UTC, as before. That coversTimestamp{P}fields, the defaultTimestamp{Microsecond}, arrays, ranges, andDateandTimefields read from timestamp text.Tbetween the date and the time, as JSON androw_to_jsonwrite it, reads withDurations.ISOTimestampFormat, including aZoffset. The old parser accepted it too, and LeagueEasy's JSON lift relies on that.DateTimefields read throughTimestamp{Microsecond}and floor to milliseconds, as before.Timestamp{Microsecond}'s range ends in year 294247, before PostgreSQL's. Past it, text with no digits finer than a millisecond reads throughTimestamp{Millisecond}, so PostgreSQL's last years still decode.tzoffset_seconds,parse_timestamptz,pg_parse_datetime_any, and the digit scanning inpg_parse_datetimeandpg_parse_timestamp. Thedateandtimeparsers stay. Dates'DateFormatparser does not compile under trim on current Julia releases, Dates: make DateFormat parse errors compile under--trim=safeJuliaLang/julia#64621 fixes that, and Durations' fix covers onlyTimestamp.infinity,-infinity, and BC values raisePostgresInterfaceError, checked before parsing.InexactError. A value outside its range raisesPostgresInterfaceErrorwith the same advice as before.ArgumentError. So on that path the driver reads the text again at microseconds, then at milliseconds, to tell them apart. Text that no resolution reads keeps Durations'ArgumentError, as malformed text did before.Behavior changes
These affect only text that PostgreSQL does not write in the ISO DateStyle the driver sets at connect, plus one corner of the range:
Tare rejected. The old parser accepted them.2024-02-13 05:28, reads with zero seconds, as Dates reads it.ArgumentErrorrather thanPostgresInterfaceError, and aDateTimefield cannot read it.Verification
Full suite.
Pkg.test()ran with Durations from Make Timestamp parsing trim-safe and read RFC 3339 text in ZonedTimestamp JuliaData/Durations.jl#10, versioned 1.5.0, andPOSTGRES_REQUIRE_INTEGRATION=trueagainstpostgres:16.DateTimeandDatefields fromtimestamptztext in theAsia/Kolkatatime zone.Dates.Timestamp: 9,304 tests pass. Trim tests skip on prereleases.Trim. On Julia 1.13.3 the verifier reports 0 counted errors, the 30 known stdlib gaps that
mainalso has, and 0 warnings.Tests. New and updated tests cover:
DateTimeandDatefields read fromtimestamptztext, LMT-era offset seconds, arrays, and the millisecond floor;DateTimefield pastTimestamp{Microsecond}'s range;Tand aZor numeric offset;Speed. Measured with
@belapsedon Julia 1.13.3, per value. Two runs agreed within 4 ns on this branch and within about 10% onmain.Timestamp, main → branchDateTime, main → branch2024-02-13 05:28:17.1234562024-02-13 05:28:17.123456+05:302024-02-13 05:28:17Text with an offset, which
timestamptzcolumns send, is faster.mainbuilt strings to read the offset and allocated 224 bytes per value, and this branch allocates none. Text without an offset, whichtimestampcolumns send, takes about twice as long. Dates' genericDateFormatparse alone takes about 51 ns. Finding the offset and reading local time into a UTCZonedTimestampadd about 25 ns more.Before merging
Register a Durations release with JuliaData/Durations.jl#10, then rerun CI.
🤖 Generated with Claude Code