rust-postgres-interval
A native Rust type for PostgreSQL's interval column, with parsing and formatting for ISO 8601, SQL, and Postgres verbose interval strings.
Repository Health
Technical Analysis
pg_interval gives Rust code a dedicated Interval type that mirrors PostgreSQL’s internal representation of the interval column type as months, days, and microseconds. Rather than forcing developers to approximate intervals with chrono::Duration or hand-roll wire-format encoding, the crate models the exact three-component structure Postgres uses internally, so round-tripping values through the database preserves their calendar semantics (a month is not always 30 days) instead of collapsing everything into a fixed-length duration.
Beyond the core type, the crate ships parsers and formatters for four distinct interval string representations — ISO 8601 (P1Y1M1DT1H), SQL standard, plain Postgres, and Postgres verbose (@ 1 hour ago) — plus optional FromSql/ToSql implementations behind a postgres feature flag for direct binary-protocol integration with the postgres and tokio-postgres crates, and lossy conversions to and from both chrono::Duration and std::time::Duration.
What You Get
- An
Intervalstruct withmonths,days, andmicrosecondsfields matching Postgres’s internal interval representation exactly - Parsers for ISO 8601, SQL standard, Postgres, and Postgres verbose (
@ ... ago) interval string formats - Matching formatters (
to_iso_8601,to_sql,to_postgres,to_postgres_verbose) to serialize anIntervalback to any of those formats - Optional
FromSql/ToSqltrait implementations (behind thepostgresfeature) for direct binary encoding/decoding with thepostgresandtokio-postgrescrates - Lossy conversion helpers to and from
chrono::Durationandstd::time::Duration, including overflow detection that returnsNoneinstead of panicking - Operator overloads (
Add/Sub) for combiningIntervalvalues
Common Use Cases
- Reading and writing
intervalcolumns from a Postgres database viapostgresortokio-postgreswithout lossy conversion to a fixed-duration type - Parsing user-supplied or config-file interval strings (e.g.
1 years 1 months 1 days 1 hours) into a typed value for scheduling or billing logic - Serializing computed durations back into Postgres-compatible interval strings for use in raw SQL or migrations
- Converting between application-level
chrono/std::timedurations and the calendar-aware interval representation Postgres expects - Building ORMs or query builders that need first-class interval support instead of falling back to strings
Under The Hood
Architecture
The crate is organized around a single core Interval struct (src/pg_interval.rs) holding months/days/microseconds, with all format-specific logic factored into parallel interval_parse and interval_fmt modules, each containing one submodule per supported format (iso_8601, sql, postgres). An interval_norm module handles the shared normalization step (converting the raw fields into years/months/days/hours/minutes/seconds/microseconds) that both the ISO 8601 and Postgres-verbose formatters build on, and pg_interval_add/pg_interval_sub isolate the Add/Sub operator implementations from the core type definition. The optional integrations module (feature-gated behind postgres) is cleanly separated from the parsing/formatting core, so consumers who only need the in-memory type and string conversions don’t pull in postgres-types or bytes at all — a clear symmetry between parse and format responsibilities that keeps each format’s logic self-contained and easy to extend.
Tech Stack
Built on Rust 2024 edition with a deliberately small dependency surface: chrono for Duration interop, bytes for the Buf/BufMut traits used in binary encode/decode, and postgres-types as an optional dependency gated behind the default-on postgres feature for FromSql/ToSql trait implementations against Postgres’s INTERVAL wire type. The crate builds with plain cargo build/cargo test, and CI (GitHub Actions, running inside a rust:alpine container) runs cargo fmt --check, cargo clippy -- -D warnings, and cargo test on every push and PR, then publishes to crates.io automatically on version tags.
Code Quality
Each module carries its own #[cfg(test)] mod tests block with focused unit tests covering both typical values and edge cases (negative intervals, overflow, sub-microsecond truncation), and CI enforces clippy -D warnings plus rustfmt --check, so the codebase stays lint-clean and consistently formatted by construction. Fallible operations use a dedicated ParseError type and Result/Option returns rather than panics — arithmetic that could overflow (e.g. from_std_duration on very large durations) explicitly uses checked_mul/checked_add and returns None on overflow instead of wrapping or panicking. Naming is consistent snake_case throughout, and the postgres-feature integration is isolated so it doesn’t leak into the core type’s test surface.
What Makes It Unique
Unlike generic duration types that flatten everything into a single elapsed-time value, pg_interval preserves the exact three-field structure (months, days, microseconds) Postgres uses internally, which matters because calendar arithmetic is not linear — “1 month” isn’t a fixed number of days. Supporting round-trip parsing and formatting across four distinct textual interval representations (ISO 8601, SQL, Postgres, and Postgres verbose) in one crate, alongside direct binary wire-format support for the postgres driver, makes it a purpose-built bridge between Rust’s duration types and Postgres’s interval semantics rather than a general-purpose duration library repurposed for the job.