julia
a3a41b56 - Dates: add `Timestamp{P}` and fractional-second format code `n` (#62994)

Commit
31 days ago
Dates: add `Timestamp{P}` and fractional-second format code `n` (#62994) * Dates: add nanosecond-precision `Timestamp` and fractional-second format code `n` `Timestamp` is an `AbstractDateTime` wrapping `UTInstant{Nanosecond}`: an `Int64` count of nanoseconds since the unix epoch 1970-01-01T00:00:00 — the physical representation shared by Apache Arrow's timestamp[ns], numpy's datetime64[ns], and pandas — making it 8 bytes, isbits, and buffer-compatible with nanosecond-timestamp columns from those systems. Nanosecond resolution in 64 bits bounds the representable range to 1677-09-21 through 2262-04-11; constructors validate the range with an Int64 comparison of (days, nanoseconds-of-day) against the type's bounds, while arithmetic is fixed-point and wraps at the ends of the range exactly as `DateTime`'s does. The type plugs into the existing generic machinery rather than duplicating it: calendrical accessors and query functions flow through `days`; calendar period arithmetic (Year/Quarter/Month) and rounding to date periods go through `Date`, so end-of-month clamping and rounding results match `DateTime`; rounding to time periods is anchored at the ISO epoch 0000-01-01, again matching `DateTime`; adjusters, function-based adjuster constructors, ranges, and `DateFormat` parsing/formatting are supported. `Timestamp` promotes with `Date` and `DateTime`; equality and ordering against those types bypass promotion and compare (day, time-of-day) pairs so comparisons against instants outside the `Timestamp` range cannot throw, and `hash` is now defined consistently with `==` across `Date`, `DateTime`, and `Timestamp`, so equal instants of different types hash alike. `now(Timestamp)` and `now(Timestamp, UTC)` read the system clock at full resolution via libuv's `uv_clock_gettime`. A new `n` format code parses and formats fractional seconds at up to nanosecond resolution (".5" is 500 milliseconds, ".123456789" is 123456789 nanoseconds; digits past the ninth must be zero, and fixed-width fields truncate to their declared width). The default `Time` format now uses it, fixing the round-trip failure where `Time` printed sub-millisecond values that its own default format could not re-parse, and the `Time` constructor's nanosecond argument may now carry a full fractional second. Parsing a `DateTime` with `n` requires the fraction to be exactly representable in milliseconds. The `firstdayof*`/`lastdayof*` adjusters and the `Time(dt)` constructor funnel are generalized from `::DateTime` to `::AbstractDateTime` so any `AbstractDateTime` subtype inherits them. Assisted-by: Claude Code (Fable 5) Assisted-by: Claude Code (Fable 5.1) Assisted-by: Codex CLI (gpt-5.6-sol) * Dates: tighten the `Timestamp` docstring Lead with the representation — an Int64 count of nanoseconds since the Unix epoch — followed by the range, the overflow behavior, and the guidance relative to `DateTime`, and move the Arrow, numpy, and pandas interoperability notes into extended help, dropping the time zone remark. Assisted-by: Claude Code (Fable 5.1) * Dates: make the `Timestamp` tests 32-bit clean The `validargs` probe passed bare integer literals, which are `Int32` on 32-bit hosts and match no `Int64`-typed method, and `2^55` overflowed `Int32` so the exact range-length check was vacuous there. Failed in CI on i686 Linux and Windows: https://buildkite.com/julialang/julia-pr/builds/2035#01a067f0-8c34-426c-a7cc-13304fccb9a9 https://buildkite.com/julialang/julia-pr/builds/2035#01a067f0-8c36-4932-9801-10317cbf3a9f Assisted-by: Claude Code (Fable 5.1) * Dates: parameterize Timestamp by resolution Support second, millisecond, microsecond, and nanosecond timestamps with Int64 Unix counts. Preserve resolution through construction and arithmetic, and require exact representation when converting to a coarser unit. Keep epoch and storage fixed while sharing calendar operations, parsing, formatting, and promotion across the four resolutions. Check rounding and range lengths at storage boundaries, and retain wrapping ordinary arithmetic. Assisted-by: Codex (GPT-6) Assisted-by: Claude Desktop (Fable 5.1) * Dates: simplify `Timestamp` docs, comments, and helpers Rewrite the `Timestamp` docstrings, the manual section, and the NEWS entries to say what the type does in fewer words. Drop text that described the change instead of the API, and drop compat notes on functions that only gained `Timestamp` methods. Code comments now describe the code next to them; one test comment said that rounding wraps, but it throws. Reuse existing machinery where it gives the same results: `Period` conversions for raw counts, period promotion to pick the finer resolution, and one (day, nanosecond of day) key for mixed comparisons and hashing. Calendar-period arithmetic wraps in plain `Int64`, which gives the same bits as the former `Int128` path. The `DateFormat` docs now advise escaping every literal letter, because new codes such as `n` can be added. Assisted-by: Claude Code (Opus 5.5) * Dates: allow package-defined Timestamp periods Let the period supply its count width and exact scale so packages can add resolutions such as Int128 picoseconds without another Timestamp representation. Use the same scale interface for conversion, promotion, arithmetic, and bounds. Assisted-by: Codex (GPT-6) * Dates: make the package-period `Timestamp` test 32-bit clean The year `10^18` is `Int32` arithmetic on 32-bit hosts and wraps to -1486618624, a year that `Date` can represent, so `Date(T(10^18))` did not throw. Use `Int64(10)^18`. Failed in CI on i686 Windows: https://buildkite.com/julialang/julia-pr/builds/2861#01a0d5b6-d424-4a7f-9de1-47ec5f4f5f55 Assisted-by: Claude Code (Opus 5.5) * Dates: plain wording for the package-defined `Timestamp` period docs Rewrite the docs and comments added for package-defined periods in plain words. The docstring said a package period needs `timestamp_scale`, but arithmetic, rounding, and ranges with the period call `Dates.tons`, and `timestamp_scale` falls back to `tons`. The package-period tests pass with `tons` alone, so the docstring now names `tons`. The rounding comment no longer says that the bounds are always `Int128`: they are `Rational` for periods shorter than a nanosecond. Assisted-by: Claude Code (Opus 5.5) * Dates: round sub-nanosecond digits down when printing a `Timestamp` A `Timestamp` of a package-defined period finer than a nanosecond could not be printed: `subsecond_nanoseconds` returned a `Rational`, which the fractional-second formatter cannot pad, so `show`, `string`, and the `n` format code threw a `MethodError`, even for a whole number of nanoseconds. Round down to whole nanoseconds, the precision of the `n` code, as the `s` code already does with digits finer than a millisecond. Assisted-by: Claude Code (Opus 5.5) * Dates: simplify `Timestamp` docs and comments Another plain-wording pass over the docstrings, comments, and NEWS added for `Timestamp`. Say "has more precision than `P`" instead of four variants of "is not a whole number of `P`", say "a full fraction of a second" for the `ns` argument, and shorten the adjuster docstring and the rounding, fraction, and field comments. Assisted-by: Claude Code (Opus 5.5) * Dates: tighten Timestamp extension and conversion boundaries Resolve equal-resolution promotion using count width and period promotion, reject unsupported timestamp scales, and avoid intermediate overflow for rational Unix seconds. Preserve millisecond formatting and expose Timestamp as a public, unexported API. Assisted-by: Codex (GPT-6) * Dates: link the manual's `Timestamp` references to `Dates.Timestamp` `Timestamp` is public but no longer exported, so `[`Timestamp`](@ref)` in the Dates manual cannot resolve and `makedocs` stops the docs build. Name the target explicitly. Failed in CI on the macOS aarch64 build: https://buildkite.com/julialang/julia-pr/builds/3096#01a0e901-d841-4811-bb62-add30c40c7d5 Assisted-by: Claude Code (Opus 5.5) * Dates: plain wording for the `Timestamp` period rules Say that one unit must divide a second evenly, and how promotion chooses between two periods with the same unit, in plain words. Assisted-by: Claude Code (Opus 5.5) * Dates: make the `Timestamp` helpers public but not exported `Timestamp` is public but not exported, so exporting `unix2timestamp`, `timestamp2unix`, and `ISOTimestampFormat` let `using Dates` code create values whose type it cannot name without the `Dates.` prefix. Make the three helpers public and unexported like `Timestamp`, and qualify or import them in the manual, the docstring examples, and the tests. Assisted-by: Claude Code (Opus 5.5) * Dates: preserve exact Timestamp arithmetic and wide counts Compute custom-period arithmetic and calendar fields using the complete nanosecond scale, including fractional scales. Widen stored counts before conversion, rounding, and range estimates so supported Int128 periods retain exact results and reject out-of-range conversions. Construct the local clock from whole seconds and raw ticks to support fractional resolutions. Assisted-by: Codex (GPT-6.1 Sol) * Dates: keep Timestamp constructor errors compatible with trim Describe the period resolution and calendar bounds with concrete string operations instead of printing Timestamp types and values. This ports the constructor-error approach from JuliaData/Durations.jl and allows native Timestamp construction errors to compile under safe trimming. Assisted-by: Codex (GPT-6.1 Sol) * Dates: require exact Timestamp period scale representations Require Integer or Rational nanoseconds per physical period unit, rejecting floating-point metadata even when it is 1.0. A floating unit previously rounded counts above 2^53 during conversion and other Timestamp operations. Apply the same validation to raw conversions, period arithmetic, rounding, and physical range steps. Preserve the calendar range estimate used for months, quarters, and years. Assisted-by: Codex (GPT-6.1 Sol)
Author
Parents
Loading