Commit graph

485 commits

Author SHA1 Message Date
Andrew Gallant
2ef6045d57
0.2.16 2025-11-07 07:53:58 -05:00
Andrew Gallant
0b293b416d
doc: a few documentation fixes 2025-11-07 07:50:44 -05:00
Andrew Gallant
0fe02f2d49 changelog: add entries for duration work 2025-11-07 07:40:15 -05:00
Abdulrazaq Alhendi
b9484eaa48 fmt/serde: add helpers for std::time::Duration
This commit writes out the Serde helpers for unsigned durations.

This is the pay off for adding the dedicated parsers/printers for a
`std::time::Duration`. Previously, we were converting to/from a
`SignedDuration`, which fundamentally limited the range of values we
could support.

Closes #380, Ref #298
2025-11-07 07:40:15 -05:00
Andrew Gallant
87c607bb72 fmt: add parsing routines for std::time::Duration
This was a little hairier than printing, but still overall pretty easy
given my previous changes!
2025-11-07 07:40:15 -05:00
Andrew Gallant
8a7f2492fd fmt: add support for printing std::time::Duration
This was thankfully as straight-forward as I was hoping!
2025-11-07 07:40:15 -05:00
Andrew Gallant
3e49cbed78 signed_duration: remove extraneous comments 2025-11-07 07:40:15 -05:00
Andrew Gallant
b5f30f2324 fmt: make fractional formatting use u32
I think when I originally wrote fractional formatting, I was thinking
about using precision values greater than `9`. But that never really
panned out. And I used signed values because I used signed values
everywhere.

I think this is the last change we need to be able to feasibly add
native `std::time::Duration` support.
2025-11-07 07:40:15 -05:00
Andrew Gallant
8e61ffd5e2 fmt: add unsigned integer formatting
... so that we can print `u64` values as-is without suspicious casts.
Unsigned integer printing is also simpler, so it's plausible that it's
faster too. Although I haven't been careful about benchmarking duration
printing.

In the next commit, we will finish removing the casts by tweaking
fractional printing.
2025-11-07 07:40:15 -05:00
Andrew Gallant
191006379b fmt: refactor friendly printer to use std::time::Duration
This is continued progress toward natively supporting
`std::time::Duration`. I basically didn't want to duplicate all of the
code used to print a `SignedDuration` just so that we could print a
`std::time::Duration`. Since we handle the sign before/after most of the
meat of printing, we can actually lower a `SignedDuration` to a
`std::time::Duration` and focus most of our printing logic from that.

There are some papercuts in this commit though. Notably, some casts
between `u64` and `i64`, since Jiff's lowest level integer printing
routine requires a `u64`. We'll fix that in the next commit.

Thank goodness I decided to make `SignedDuration` mimic
`std::time::Duration` exactly (except for being signed). That made this
change super easy.
2025-11-07 07:40:15 -05:00
Andrew Gallant
9b46e2e0c1 fmt: optimize parsing into Span
We do something similar like we did for `SignedDuration`: we carve out a
fast path that generally lets us quickly skip error checking and what
not. Overall comparison with current `master`
(211a36d5ec):

    group                                             master                                 new
    -----                                             ------                                 ---
    parse/friendly/long/span/jiff                     3.26    104.3±0.48ns        ? ?/sec    1.00     32.0±0.34ns        ? ?/sec
    parse/friendly/longer/span/jiff                   3.18    105.7±0.35ns        ? ?/sec    1.00     33.2±0.20ns        ? ?/sec
    parse/friendly/longest-time/duration/jiff         1.26     41.9±0.69ns        ? ?/sec    1.00     33.3±0.62ns        ? ?/sec
    parse/friendly/longest-time/span/jiff             3.31    122.1±0.32ns        ? ?/sec    1.00     36.8±0.28ns        ? ?/sec
    parse/friendly/longest/span/jiff                  3.22    160.5±0.48ns        ? ?/sec    1.00     49.8±0.47ns        ? ?/sec
    parse/friendly/medium/span/jiff                   2.93     62.3±0.13ns        ? ?/sec    1.00     21.2±0.16ns        ? ?/sec
    parse/friendly/short/duration/jiff                1.20     15.7±0.27ns        ? ?/sec    1.00     13.0±0.25ns        ? ?/sec
    parse/friendly/short/span/jiff                    2.69     49.8±0.19ns        ? ?/sec    1.00     18.5±0.04ns        ? ?/sec
    parse/friendly/tiny/duration/jiff                 1.08      8.1±0.36ns        ? ?/sec    1.00      7.5±0.13ns        ? ?/sec
    parse/friendly/tiny/span/jiff                     2.09     34.1±0.11ns        ? ?/sec    1.00     16.3±0.08ns        ? ?/sec
    parse/iso8601_duration/long-time/duration/jiff    1.12     27.6±0.32ns        ? ?/sec    1.00     24.7±0.22ns        ? ?/sec
    parse/iso8601_duration/long-time/span/jiff        1.28     76.6±0.17ns        ? ?/sec    1.00     59.7±0.23ns        ? ?/sec
    parse/iso8601_duration/long/span/jiff             4.36    101.8±0.21ns        ? ?/sec    1.00     23.4±0.14ns        ? ?/sec
    parse/iso8601_duration/medium/span/jiff           3.18     60.3±0.12ns        ? ?/sec    1.00     19.0±0.11ns        ? ?/sec
    parse/iso8601_duration/short/duration/jiff        1.49     12.1±0.22ns        ? ?/sec    1.00      8.1±0.14ns        ? ?/sec
    parse/iso8601_duration/short/span/jiff            2.68     47.7±0.12ns        ? ?/sec    1.00     17.8±0.22ns        ? ?/sec
    parse/iso8601_duration/tiny/duration/jiff         1.10      6.7±0.10ns        ? ?/sec    1.00      6.0±0.06ns        ? ?/sec
    parse/iso8601_duration/tiny/span/jiff             2.00     33.1±0.08ns        ? ?/sec    1.00     16.5±0.08ns        ? ?/sec

Very happy with this. Especially getting some of the 100ns+ benchmarks
down to something much more reasonable is amazing.
2025-11-07 07:40:15 -05:00
Andrew Gallant
1cb039f707 fmt: fix i64::MIN bug in ISO 8601 duration parsing
This only applies to parsing into a `SignedDuration` since `i64::MIN`
isn't supported by any units on `Span` (including nanoseconds, since it
only supports `(i64::MIN+1)..=i64::MAX` to make negations infallible).

We pull out the u64 prefix parser from the friendly duration and use
that. Since that does the parsing in a single pass and is overall
generally tighter, this also leads to a nice perf improvement on ISO
8601 duration parsing:

    group                                             master                                 new
    -----                                             ------                                 ---
    parse/iso8601_duration/long-time/duration/jiff    1.14     27.6±0.32ns        ? ?/sec    1.00     24.2±0.24ns        ? ?/sec
    parse/iso8601_duration/long-time/span/jiff        1.21     76.6±0.17ns        ? ?/sec    1.00     63.2±0.24ns        ? ?/sec
    parse/iso8601_duration/long/span/jiff             2.14    101.8±0.21ns        ? ?/sec    1.00     47.4±0.24ns        ? ?/sec
    parse/iso8601_duration/medium/span/jiff           1.71     60.3±0.12ns        ? ?/sec    1.00     35.2±0.12ns        ? ?/sec
    parse/iso8601_duration/short/duration/jiff        1.56     12.1±0.22ns        ? ?/sec    1.00      7.8±0.13ns        ? ?/sec
    parse/iso8601_duration/short/span/jiff            1.50     47.7±0.12ns        ? ?/sec    1.00     31.9±0.08ns        ? ?/sec
    parse/iso8601_duration/tiny/duration/jiff         1.17      6.7±0.10ns        ? ?/sec    1.00      5.7±0.03ns        ? ?/sec
    parse/iso8601_duration/tiny/span/jiff             1.19     33.1±0.08ns        ? ?/sec    1.00     27.8±0.10ns        ? ?/sec

The results above are compared against current `master`
(`211a36d5ecddf1aeb9b00648d9d5e631a5420903`).
2025-11-07 07:40:15 -05:00
Andrew Gallant
206f08100d fmt: more clean up
This DRY's up some code and tightens up a few things.
2025-11-07 07:40:15 -05:00
Andrew Gallant
8f75807b5e fmt: optimize parsing SignedDuration
The "before" here reflects `master`
(`211a36d5ec`) and not the previous
commit:

    group                                             master                                 new
    -----                                             ------                                 ---
    parse/friendly/longest-time/duration/jiff         1.29     41.9±0.69ns        ? ?/sec    1.00     32.4±0.42ns        ? ?/sec
    parse/friendly/short/duration/jiff                1.14     15.7±0.27ns        ? ?/sec    1.00     13.8±0.30ns        ? ?/sec
    parse/friendly/tiny/duration/jiff                 1.23      8.1±0.36ns        ? ?/sec    1.00      6.6±0.11ns        ? ?/sec
    parse/iso8601_duration/long-time/duration/jiff    1.00     27.6±0.32ns        ? ?/sec    1.06     29.3±0.27ns        ? ?/sec
    parse/iso8601_duration/short/duration/jiff        1.05     12.1±0.22ns        ? ?/sec    1.00     11.5±0.20ns        ? ?/sec
    parse/iso8601_duration/tiny/duration/jiff         1.00      6.7±0.10ns        ? ?/sec    1.15      7.7±0.09ns        ? ?/sec

There are some minor regressions, but also some wins, particularly for
the friendly format.

I mostly focused on optimizing the "turn parsed values into a
`SignedDuration`" part. I used a data dependent optimization that
quickly detects whether we can avoid error handling entirely.

We could probably optimize the general case a bit more too. But this is
enough for now.
2025-11-07 07:40:15 -05:00
Andrew Gallant
ce51de3982 fmt: massively refactor duration parsing
This introduces a new internal helper type, `DurationUnits`, that is
used to parse all duration types and formats. It centralizes the logic
and trims away a lot of fat. This should reduce code size (although I
haven't checked) and also improve perf. Currently, it does significantly
improve perf for parsing longer durations and especially for `Span`. It
does however slightly regress perf for parsing shorter `SignedDuration`
values.

However, I think there are a lot of perf improvement opportunities. I'll
put those in a subsequent commit.

(We still haven't implemented `std::time::Duration` yet. But
`DurationUnits` is clearly designed with it in mind. This is one helluva
yak shave!)

This also fixes a long-standing bug where we couldn't parse
`abs(i64::MIN) secs ago`. The `DurationUnits` design was specifically
motivated (in part) by this.
2025-11-07 07:40:15 -05:00
Andrew Gallant
da7a745635 zoned: fix copy & paste transcription error 2025-11-07 07:40:15 -05:00
Andrew Gallant
53db0d137e fmt: remove another ranged integer
Specifically, the ranged integer used when parsing fractional
values. We'll want to do this in order to switch over to parsing
durations into a single shared unified type.
2025-11-07 07:40:15 -05:00
Andrew Gallant
729374ba20 fmt: slight simplification
This lets me un-export `Decimal::new`. A small matter.
2025-11-07 07:40:15 -05:00
Andrew Gallant
00e630b76f fmt: rip out some uses of ranged integers
In particular, `NoUnits` and `NoUnits128`.

I dare say that this might be (the very) beginning of getting
away from ranged integers. The specific motivation here is that
we want to be able to parse `std::time::Duration`. And to do that,
we need to be able to parse a `u64`. But before this commit, we
were parsing into a `t::NoUnits`, which is an `i64`. And we don't
have unsigned ranged integers and I refused to go down that path.
So we need to use a `u64` because I refuse to use an `i128` any
time we want to parse an integer.
2025-11-07 07:40:15 -05:00
Andrew Gallant
61e329d7f0 signed_duration: add i128 constructors
... and also a smattering of internal helpers.

The `SignedDuration::from_nanos_i128` constructor in particular
is analogous to `std::time::Duration::from_nanos_u128` coming to
a `std` near you. The rest are just a logical continuation.

This also adds some "get units with a remainder" methods that
I think will be useful in simplifying some of the duration
parsing code.
2025-11-07 07:40:15 -05:00
Andrew Gallant
c2d4846258 signed_duration: move constants to the top
I think this is a more natural place for them. In particular,
I kept going to the top of the file to look for them and then
needing to scroll down through a bunch of docs.
2025-11-07 07:40:15 -05:00
Andrew Gallant
53d41c53be fmt: slightly refactor duration parsing
This brings the code for parsing duration strings (ISO 8601 and
friendly) into `SignedDuration` or `Span` into more alignment.

There are still some annoying differences. And some bugs I
(re)discovered. They are marked as TODOs in this commit.

The main motivation here is to support parsing into
`std::time::Duration`. A third copy of this code was too unappealing to
me, so I'm trying to refactor the code to make it tighter and less
redundant.
2025-11-07 07:40:15 -05:00
Andrew Gallant
d8816b6a1c fmt/friendly: simplify set_span_unit_value
This is a slight refactor to reduce a little duplication.

I don't mind duplication, but in this case, I was wondering why
this block was repeated and had to very carefully scrutinize the
code to follow it and make sure there weren't any differences. DRY
in this case I think makes it easier to understand.
2025-11-07 07:40:15 -05:00
jesse
64940a824b
doc: typo fixing
Some checks are pending
ci / test-core (nightly, ubuntu-latest, nightly) (push) Waiting to run
ci / test-various-feature-combos (macos, macos-latest, nightly) (push) Waiting to run
ci / test-various-feature-combos (nightly, ubuntu-latest, nightly) (push) Waiting to run
ci / test-release (push) Waiting to run
ci / test-doc (push) Waiting to run
ci / test-bench (push) Waiting to run
ci / test-miri (push) Waiting to run
ci / win-msvc (push) Waiting to run
ci / win-gnu (push) Waiting to run
ci / msrv (push) Waiting to run
ci / examples (push) Waiting to run
ci / integrations (push) Waiting to run
ci / time-zone-init (macos-latest) (push) Waiting to run
ci / time-zone-init (ubuntu-24.04-arm) (push) Waiting to run
ci / time-zone-init (ubuntu-latest) (push) Waiting to run
ci / cross (aarch64-unknown-linux-gnu) (push) Waiting to run
ci / cross (i686-unknown-linux-gnu) (push) Waiting to run
ci / time-zone-init (windows-latest) (push) Waiting to run
ci / cross (aarch64-linux-android) (push) Waiting to run
ci / cross (powerpc-unknown-linux-gnu) (push) Waiting to run
ci / cross (powerpc64-unknown-linux-gnu) (push) Waiting to run
ci / cross (s390x-unknown-linux-gnu) (push) Waiting to run
ci / cross (x86_64-linux-android) (push) Waiting to run
ci / riscv32imc-unknown-none-elf (push) Waiting to run
ci / wasm32-wasip1 (push) Waiting to run
ci / wasm32-unknown-emscripten (push) Waiting to run
ci / wasm32-unknown-uknown (push) Waiting to run
ci / docsrs (push) Waiting to run
ci / rustfmt (push) Waiting to run
ci / generated (push) Waiting to run
Mostly found via `typos-cli` and `codespell`.

PR #443
2025-11-06 16:11:16 -05:00
Andrew Gallant
211a36d5ec
bench: add benchmarks for parsing ISO 8601 durations
Some checks failed
ci / docsrs (push) Has been cancelled
ci / rustfmt (push) Has been cancelled
ci / test-core (nightly, ubuntu-latest, nightly) (push) Has been cancelled
ci / test-various-feature-combos (macos, macos-latest, nightly) (push) Has been cancelled
ci / test-various-feature-combos (nightly, ubuntu-latest, nightly) (push) Has been cancelled
ci / test-release (push) Has been cancelled
ci / test-doc (push) Has been cancelled
ci / test-bench (push) Has been cancelled
ci / test-miri (push) Has been cancelled
ci / win-msvc (push) Has been cancelled
ci / win-gnu (push) Has been cancelled
ci / msrv (push) Has been cancelled
ci / examples (push) Has been cancelled
ci / integrations (push) Has been cancelled
ci / time-zone-init (macos-latest) (push) Has been cancelled
ci / time-zone-init (ubuntu-24.04-arm) (push) Has been cancelled
ci / time-zone-init (ubuntu-latest) (push) Has been cancelled
ci / time-zone-init (windows-latest) (push) Has been cancelled
ci / cross (aarch64-linux-android) (push) Has been cancelled
ci / cross (aarch64-unknown-linux-gnu) (push) Has been cancelled
ci / cross (i686-unknown-linux-gnu) (push) Has been cancelled
ci / cross (powerpc-unknown-linux-gnu) (push) Has been cancelled
ci / cross (powerpc64-unknown-linux-gnu) (push) Has been cancelled
ci / cross (s390x-unknown-linux-gnu) (push) Has been cancelled
ci / cross (x86_64-linux-android) (push) Has been cancelled
ci / riscv32imc-unknown-none-elf (push) Has been cancelled
ci / wasm32-wasip1 (push) Has been cancelled
ci / wasm32-unknown-emscripten (push) Has been cancelled
ci / wasm32-unknown-uknown (push) Has been cancelled
ci / generated (push) Has been cancelled
I'm kind of surprised I hadn't added these yet. But I think among Jiff,
Chrono and `time`, Jiff is the only one to support them.

I'm going to be touching the implementation (in persuit of adding
support for parsing/printing `std::time::Duration` directly), so I want
to make sure I am at least not regressing perf.
2025-10-29 21:31:31 -04:00
jesse
aae54ca665
api: actually export ZonedSeries
Some checks failed
ci / time-zone-init (ubuntu-latest) (push) Has been cancelled
ci / test-default (beta, ubuntu-latest, beta) (push) Has been cancelled
ci / test-default (macos, macos-latest, stable) (push) Has been cancelled
ci / test-default (nightly, ubuntu-latest, nightly) (push) Has been cancelled
ci / test-default (stable, ubuntu-latest, stable) (push) Has been cancelled
ci / test-all (macos, macos-latest, nightly) (push) Has been cancelled
ci / test-all (nightly, ubuntu-latest, nightly) (push) Has been cancelled
ci / test-only-bundle (macos, macos-latest, nightly) (push) Has been cancelled
ci / test-only-bundle (nightly, ubuntu-latest, nightly) (push) Has been cancelled
ci / test-core (macos, macos-latest, nightly) (push) Has been cancelled
ci / test-core (nightly, ubuntu-latest, nightly) (push) Has been cancelled
ci / test-various-feature-combos (macos, macos-latest, nightly) (push) Has been cancelled
ci / test-various-feature-combos (nightly, ubuntu-latest, nightly) (push) Has been cancelled
ci / test-release (push) Has been cancelled
ci / test-doc (push) Has been cancelled
ci / test-bench (push) Has been cancelled
ci / cross (aarch64-linux-android) (push) Has been cancelled
ci / cross (aarch64-unknown-linux-gnu) (push) Has been cancelled
ci / wasm32-wasip1 (push) Has been cancelled
ci / wasm32-unknown-emscripten (push) Has been cancelled
ci / cross (i686-unknown-linux-gnu) (push) Has been cancelled
ci / cross (powerpc-unknown-linux-gnu) (push) Has been cancelled
ci / cross (powerpc64-unknown-linux-gnu) (push) Has been cancelled
ci / cross (s390x-unknown-linux-gnu) (push) Has been cancelled
ci / cross (x86_64-linux-android) (push) Has been cancelled
ci / riscv32imc-unknown-none-elf (push) Has been cancelled
ci / rustfmt (push) Has been cancelled
ci / generated (push) Has been cancelled
ci / wasm32-unknown-uknown (push) Has been cancelled
ci / docsrs (push) Has been cancelled
This was an oversight that I missed in #430.

PR #442
2025-10-27 14:19:02 -04:00
Owen Walpole
4b44d13192
doc: fix typo in Zoned type documentation
PR #441
2025-10-27 11:15:35 -04:00
Andrew Gallant
f92871a2c7
tests: improve test failure message
Some checks failed
ci / test-core (macos, macos-latest, nightly) (push) Has been cancelled
ci / test-various-feature-combos (macos, macos-latest, nightly) (push) Has been cancelled
ci / test-various-feature-combos (nightly, ubuntu-latest, nightly) (push) Has been cancelled
ci / test-release (push) Has been cancelled
ci / test-doc (push) Has been cancelled
ci / test-bench (push) Has been cancelled
ci / test-miri (push) Has been cancelled
ci / win-msvc (push) Has been cancelled
ci / win-gnu (push) Has been cancelled
ci / msrv (push) Has been cancelled
ci / integrations (push) Has been cancelled
ci / examples (push) Has been cancelled
ci / time-zone-init (macos-latest) (push) Has been cancelled
ci / time-zone-init (ubuntu-24.04-arm) (push) Has been cancelled
ci / time-zone-init (ubuntu-latest) (push) Has been cancelled
ci / time-zone-init (windows-latest) (push) Has been cancelled
ci / cross (aarch64-linux-android) (push) Has been cancelled
ci / cross (aarch64-unknown-linux-gnu) (push) Has been cancelled
ci / cross (i686-unknown-linux-gnu) (push) Has been cancelled
ci / cross (s390x-unknown-linux-gnu) (push) Has been cancelled
ci / cross (x86_64-linux-android) (push) Has been cancelled
ci / cross (powerpc-unknown-linux-gnu) (push) Has been cancelled
ci / cross (powerpc64-unknown-linux-gnu) (push) Has been cancelled
ci / riscv32imc-unknown-none-elf (push) Has been cancelled
ci / wasm32-wasip1 (push) Has been cancelled
ci / wasm32-unknown-emscripten (push) Has been cancelled
ci / wasm32-unknown-uknown (push) Has been cancelled
ci / docsrs (push) Has been cancelled
ci / rustfmt (push) Has been cancelled
ci / generated (push) Has been cancelled
This test is failing intermittently on macOS. Which means that the
initialization of the zoneinfo database is taking more than 500ms. I had
scrutinized the CI logs and timestamps, and it looks like it's just
random I/O delay when traversing the zoneinfo directory. Sigh.
2025-10-23 13:27:12 -04:00
Andrew Gallant
8383ebf05f
shared: remove commented out code 2025-10-23 13:12:20 -04:00
Andrew Gallant
292f18640d posix: fix handling of "permanent DST" POSIX time zone strings
See the comment in the code for explanation, but basically, this comes
from S 3.3.1 of RFC 9636:

> 3.3.1.  All-Year Daylight Saving Time
>
> DST is considered to be in effect all year if its UT offset is less
> than (i.e., west of) that of standard time, and it starts January 1
> at 00:00 and ends December 31 at 24:00 minus the difference between
> standard and daylight saving time, leaving no room for standard time
> in the calendar.  [POSIX] implies but does not explicitly state this,
> so it is spelled out here for clarity.
>
> Example: XXX3EDT4,0/0,J365/23

> This represents a time zone that is perpetually 4 hours west of UT
> and is abbreviated "EDT".  The "XXX" is ignored.

These odd time zones can occur when compiling TZif files using `zic`
with rearguard semantics. In particular, this applies for times at or
after 2087 in `Africa/Casablanca`. Rearguard semantics are used by
Jiff's `jiff-tzdb` crate, but aren't always otherwise used in standard
`/usr/share/zoneinfo` installations. As a result, this bug's effects
cannot always be consistently observed.

Fixes #386
2025-10-23 08:57:53 -04:00
Andrew Gallant
06564abdf4 dev: improve Debug experience for PosixTimeZone
This commit adds a few targeted `Debug` constraints so that
we can use `dbg!` a bit more freely.
2025-10-23 08:57:53 -04:00
Andrew Gallant
5b4a131ee7 changelog: include changes since the 0.2.15 release
Some checks failed
ci / test-core (nightly, ubuntu-latest, nightly) (push) Has been cancelled
ci / test-various-feature-combos (macos, macos-latest, nightly) (push) Has been cancelled
ci / test-various-feature-combos (nightly, ubuntu-latest, nightly) (push) Has been cancelled
ci / test-release (push) Has been cancelled
ci / test-doc (push) Has been cancelled
ci / test-bench (push) Has been cancelled
ci / test-miri (push) Has been cancelled
ci / test-default (beta, ubuntu-latest, beta) (push) Has been cancelled
ci / test-default (nightly, ubuntu-latest, nightly) (push) Has been cancelled
ci / test-default (stable, ubuntu-latest, stable) (push) Has been cancelled
ci / test-all (macos, macos-latest, nightly) (push) Has been cancelled
ci / test-all (nightly, ubuntu-latest, nightly) (push) Has been cancelled
ci / test-only-bundle (macos, macos-latest, nightly) (push) Has been cancelled
ci / test-only-bundle (nightly, ubuntu-latest, nightly) (push) Has been cancelled
ci / time-zone-init (ubuntu-latest) (push) Has been cancelled
ci / cross (aarch64-unknown-linux-gnu) (push) Has been cancelled
ci / cross (i686-unknown-linux-gnu) (push) Has been cancelled
ci / cross (powerpc-unknown-linux-gnu) (push) Has been cancelled
ci / cross (powerpc64-unknown-linux-gnu) (push) Has been cancelled
ci / cross (s390x-unknown-linux-gnu) (push) Has been cancelled
ci / cross (x86_64-linux-android) (push) Has been cancelled
ci / riscv32imc-unknown-none-elf (push) Has been cancelled
ci / wasm32-wasip1 (push) Has been cancelled
ci / time-zone-init (windows-latest) (push) Has been cancelled
ci / cross (aarch64-linux-android) (push) Has been cancelled
ci / wasm32-unknown-emscripten (push) Has been cancelled
ci / wasm32-unknown-uknown (push) Has been cancelled
ci / docsrs (push) Has been cancelled
ci / rustfmt (push) Has been cancelled
ci / generated (push) Has been cancelled
It looks like I only captured some of them. But there were seveal I
omitted.

(This is why I don't keep a CHANGELOG in most projects. It adds a lot of
maintenance overhead.)
2025-10-19 11:54:18 -04:00
Andrew Gallant
1d04e6a1be
changelog: add note about #396
I routinely forget to add to the CHANGELOG. Ugh.
2025-10-19 09:28:59 -04:00
Andrew Gallant
ba99ee49b4 zoned: add arithmetic impls for Zoned
Previously, we only had impls for `&Zoned`. These impls are a little
weird because `Zoned` isn't `Copy`. So using them will result in
consuming the `Zoned` value. But if that's okay, then having these impls
is a nice quality of life improvement instead of a papercut. In the
worst case, Rust programmers will need to add a `&` to avoid consuming
the `Zoned` value. But I think Rust programmers are pretty used to that.

Fixes #396
2025-10-19 09:27:43 -04:00
Andrew Gallant
23cdd25454 fmt/strtime: make strptime with Zoned and only %s work
Some checks are pending
ci / time-zone-init (ubuntu-latest) (push) Waiting to run
ci / time-zone-init (windows-latest) (push) Waiting to run
ci / win-msvc (push) Waiting to run
ci / test-default (beta, ubuntu-latest, beta) (push) Waiting to run
ci / test-default (macos, macos-latest, stable) (push) Waiting to run
ci / test-default (nightly, ubuntu-latest, nightly) (push) Waiting to run
ci / test-default (stable, ubuntu-latest, stable) (push) Waiting to run
ci / test-all (macos, macos-latest, nightly) (push) Waiting to run
ci / test-all (nightly, ubuntu-latest, nightly) (push) Waiting to run
ci / test-only-bundle (macos, macos-latest, nightly) (push) Waiting to run
ci / test-only-bundle (nightly, ubuntu-latest, nightly) (push) Waiting to run
ci / test-core (macos, macos-latest, nightly) (push) Waiting to run
ci / test-core (nightly, ubuntu-latest, nightly) (push) Waiting to run
ci / test-various-feature-combos (macos, macos-latest, nightly) (push) Waiting to run
ci / test-various-feature-combos (nightly, ubuntu-latest, nightly) (push) Waiting to run
ci / wasm32-wasip1 (push) Waiting to run
ci / wasm32-unknown-emscripten (push) Waiting to run
ci / wasm32-unknown-uknown (push) Waiting to run
ci / rustfmt (push) Waiting to run
ci / generated (push) Waiting to run
ci / test-release (push) Waiting to run
ci / cross (aarch64-linux-android) (push) Waiting to run
ci / cross (aarch64-unknown-linux-gnu) (push) Waiting to run
ci / cross (i686-unknown-linux-gnu) (push) Waiting to run
ci / cross (powerpc-unknown-linux-gnu) (push) Waiting to run
ci / cross (powerpc64-unknown-linux-gnu) (push) Waiting to run
ci / cross (s390x-unknown-linux-gnu) (push) Waiting to run
ci / cross (x86_64-linux-android) (push) Waiting to run
ci / riscv32imc-unknown-none-elf (push) Waiting to run
ci / docsrs (push) Waiting to run
Previously, if `%s` was parsed and there was no offset (`%z`) or IANA
time zone identifier (`%Q`), then trying to pull a `Zoned` out of a
`BrokenDownTime` would fail. But arguably, this should work. Namely, the
`strptime` APIs are already very relaxed about returning a `Zoned` with
fixed offset time zones (where the normal `FromStr` APIs forbid it due
to footguns). And since we have a way of representing an unknown time
zone, we can do exactly that.
2025-10-18 15:04:20 -04:00
Andrew Gallant
fdf6ab2978 fmt/strtime: make behavior of BrokenDownTime::to_timestamp a bit more consistent
Some checks are pending
ci / test-all (nightly, ubuntu-latest, nightly) (push) Waiting to run
ci / test-only-bundle (macos, macos-latest, nightly) (push) Waiting to run
ci / test-only-bundle (nightly, ubuntu-latest, nightly) (push) Waiting to run
ci / test-core (macos, macos-latest, nightly) (push) Waiting to run
ci / test-core (nightly, ubuntu-latest, nightly) (push) Waiting to run
ci / test-various-feature-combos (macos, macos-latest, nightly) (push) Waiting to run
ci / test-various-feature-combos (nightly, ubuntu-latest, nightly) (push) Waiting to run
ci / test-release (push) Waiting to run
ci / win-msvc (push) Waiting to run
ci / win-gnu (push) Waiting to run
ci / msrv (push) Waiting to run
ci / examples (push) Waiting to run
ci / integrations (push) Waiting to run
ci / time-zone-init (macos-latest) (push) Waiting to run
ci / time-zone-init (ubuntu-24.04-arm) (push) Waiting to run
ci / time-zone-init (ubuntu-latest) (push) Waiting to run
ci / cross (aarch64-linux-android) (push) Waiting to run
ci / cross (aarch64-unknown-linux-gnu) (push) Waiting to run
ci / cross (i686-unknown-linux-gnu) (push) Waiting to run
ci / cross (powerpc-unknown-linux-gnu) (push) Waiting to run
ci / cross (powerpc64-unknown-linux-gnu) (push) Waiting to run
ci / cross (s390x-unknown-linux-gnu) (push) Waiting to run
ci / cross (x86_64-linux-android) (push) Waiting to run
ci / riscv32imc-unknown-none-elf (push) Waiting to run
ci / wasm32-wasip1 (push) Waiting to run
ci / wasm32-unknown-emscripten (push) Waiting to run
ci / wasm32-unknown-uknown (push) Waiting to run
ci / docsrs (push) Waiting to run
ci / rustfmt (push) Waiting to run
ci / generated (push) Waiting to run
Specifically, all of the other higher level constructors on
`BrokenDownTime` already try their "hardest" to produce the
requested value. Notably, both `BrokenDownTime::to_date` and
`BrokenDownTime::to_time` go to some effort to achieve this.

However, `BrokenDownTime::to_timestamp` wasn't doing everything it
could. Namely, it was completely ignoring its internal `timestamp`
field. This is weird and inconsistent from how the rest of the
constructors worked.

I think this is overall more flexible as well. Because it means that
parsing `%s` is, at the level of the individual pieces of data inside a
`BrokenDownTime`, completely separate from everything else. So you don't
have any weird overwriting behavior at the lowest levels.

I started thinking about this in #428. While I don't think the
motivation in #428 is that compelling, it got me thinking more deeply
about how a `BrokenDownTime` deals with timestamps. I think we got to
this state because I bolted `%s` on to `fmt::strtime` and didn't think
deeply about it.

Fixes #428
2025-10-17 14:54:03 -04:00
Andrew Gallant
6045e178a0 fmt/strtime: relax formatting of %y and %g
Previously, these would fail if the year wasn't in the range
`1969-2068`. This was done because parsing fails for the same reason,
and it seemed like good sense to have parsing and formatting be
consistent with one another.

... however, this is the *only* formatting specifier that can yield an
error based on the specific values provided. In contrast, all other
errors are tied to either the validity of the formatting string or if
all relevant data is provided (i.e., you get an error if you use `%y`
and your `BrokenDownTime` doesn't have a way to get the year).

I don't think this aberration is worth it. I think it's better to be
able to say the two broad error categories and be able to stick to them.
This should also hopefully avoid accidental panics, since now the only
error conditions that result in, say, `Zoned::strftime` panicking are
limited to the format string itself.

Fixes #428
2025-10-17 14:54:03 -04:00
Andrew Gallant
860b58a3c4 fmt/strtime: make lenient formatting more lenient
Previously, it was possible for lenient formatting to still error when
the formatting string contained invalid UTF-8. This commit alleviates
that error condition by writing a replacement character instead. This
required tweaking our UTF-8 decoding routines so that we could implement
the "substitution by maximal subparts" strategy for lossy decoding.

This now means that lenient formatting can only fail when writing to the
underlying writer fails.
2025-10-17 14:54:03 -04:00
Andrew Gallant
ee139f5a2b api: add Zoned::series
Some checks failed
ci / win-gnu (push) Has been cancelled
ci / test-doc (push) Has been cancelled
ci / test-bench (push) Has been cancelled
ci / test-default (beta, ubuntu-latest, beta) (push) Has been cancelled
ci / test-default (macos, macos-latest, stable) (push) Has been cancelled
ci / test-default (nightly, ubuntu-latest, nightly) (push) Has been cancelled
ci / test-default (stable, ubuntu-latest, stable) (push) Has been cancelled
ci / test-all (macos, macos-latest, nightly) (push) Has been cancelled
ci / test-all (nightly, ubuntu-latest, nightly) (push) Has been cancelled
ci / test-only-bundle (macos, macos-latest, nightly) (push) Has been cancelled
ci / test-only-bundle (nightly, ubuntu-latest, nightly) (push) Has been cancelled
ci / test-core (macos, macos-latest, nightly) (push) Has been cancelled
ci / test-core (nightly, ubuntu-latest, nightly) (push) Has been cancelled
ci / test-various-feature-combos (macos, macos-latest, nightly) (push) Has been cancelled
ci / test-various-feature-combos (nightly, ubuntu-latest, nightly) (push) Has been cancelled
ci / test-release (push) Has been cancelled
ci / cross (aarch64-linux-android) (push) Has been cancelled
ci / cross (aarch64-unknown-linux-gnu) (push) Has been cancelled
ci / cross (i686-unknown-linux-gnu) (push) Has been cancelled
ci / cross (powerpc-unknown-linux-gnu) (push) Has been cancelled
ci / cross (powerpc64-unknown-linux-gnu) (push) Has been cancelled
ci / cross (s390x-unknown-linux-gnu) (push) Has been cancelled
ci / cross (x86_64-linux-android) (push) Has been cancelled
ci / riscv32imc-unknown-none-elf (push) Has been cancelled
ci / wasm32-wasip1 (push) Has been cancelled
ci / wasm32-unknown-emscripten (push) Has been cancelled
ci / wasm32-unknown-uknown (push) Has been cancelled
ci / docsrs (push) Has been cancelled
ci / rustfmt (push) Has been cancelled
ci / generated (push) Has been cancelled
I had been uncertain about how this should be implemented in the face of
truly aberrant time zone transitions (like 2011-12-30 being missing from
`Pacific/Apia`). But this particular method is incredibly useful _and_
is present on all of the other datetime types. So I think it's important
enough to add, even if it may have somewhat odd semantics in some cases.

In particular, if we implement `Zoned::series` like we do
`civil::DateTime::series`, then a time series over spans of `1 day`
starting on `2011-12-29` in `Pacific/Apia` will result in yielding
`2011-12-31` twice. This is because `2011-12-29 + 1 day` and
`2011-12-29 + 2 days` are equivalent (i.e., `2011-12-30`) in
`Pacific/Apia`. Indeed, this behavior is copied from Temporal which
behaves the same:

    >>> zdt = Temporal.ZonedDateTime.from("2011-12-29[Pacific/Apia]")
    Object { … }
    >>> zdt.toString()
    "2011-12-29T00:00:00-10:00[Pacific/Apia]"
    >>> zdt.add({days: 1}).toString()
    "2011-12-31T00:00:00+14:00[Pacific/Apia]"
    >>> zdt.add({days: 2}).toString()
    "2011-12-31T00:00:00+14:00[Pacific/Apia]"

I think yielding the same instant twice in a row is perhaps very odd and
unexpected. Instead, the iterator guarantees that each item yielded by
the iterator is strictly greater (or strictly less for negative spans)
than the one that precedes it. This fixes the `Pacific/Apia` case while
preserving the same kind of semantics we get with
`civil::DateTime::series`.
2025-10-15 12:30:13 -04:00
Andrew Gallant
1e3af6951e
fmt: add more examples for BrokenDownTime::to_timestamp
Some checks failed
ci / test-default (beta, ubuntu-latest, beta) (push) Has been cancelled
ci / test-default (macos, macos-latest, stable) (push) Has been cancelled
ci / test-default (nightly, ubuntu-latest, nightly) (push) Has been cancelled
ci / test-default (stable, ubuntu-latest, stable) (push) Has been cancelled
ci / test-all (macos, macos-latest, nightly) (push) Has been cancelled
ci / test-all (nightly, ubuntu-latest, nightly) (push) Has been cancelled
ci / test-only-bundle (macos, macos-latest, nightly) (push) Has been cancelled
ci / test-only-bundle (nightly, ubuntu-latest, nightly) (push) Has been cancelled
ci / test-various-feature-combos (macos, macos-latest, nightly) (push) Has been cancelled
ci / test-various-feature-combos (nightly, ubuntu-latest, nightly) (push) Has been cancelled
ci / test-release (push) Has been cancelled
ci / test-doc (push) Has been cancelled
ci / test-bench (push) Has been cancelled
ci / test-miri (push) Has been cancelled
ci / win-msvc (push) Has been cancelled
ci / win-gnu (push) Has been cancelled
ci / cross (aarch64-linux-android) (push) Has been cancelled
ci / cross (aarch64-unknown-linux-gnu) (push) Has been cancelled
ci / cross (i686-unknown-linux-gnu) (push) Has been cancelled
ci / cross (powerpc-unknown-linux-gnu) (push) Has been cancelled
ci / cross (powerpc64-unknown-linux-gnu) (push) Has been cancelled
ci / cross (s390x-unknown-linux-gnu) (push) Has been cancelled
ci / cross (x86_64-linux-android) (push) Has been cancelled
ci / riscv32imc-unknown-none-elf (push) Has been cancelled
ci / wasm32-wasip1 (push) Has been cancelled
ci / wasm32-unknown-emscripten (push) Has been cancelled
ci / wasm32-unknown-uknown (push) Has been cancelled
ci / docsrs (push) Has been cancelled
ci / rustfmt (push) Has been cancelled
ci / generated (push) Has been cancelled
Specifically, document what happens when there is conflicting data
parsed with `%s` and, say, `%Y-%m-%d`.

This is a good example of why `strptime` is kinda fucked up, but on the
same token, somewhat pragmatic in its utility.
2025-10-13 14:06:14 -04:00
Andrew Gallant
a4ed213770 ci: bump actions/checkout from v4 to v5 2025-10-13 12:50:49 -04:00
Andrew Gallant
0099c91ec4 doc: switch from doc_auto_cfg to doc_cfg
In https://github.com/rust-lang/rust/pull/138907, the `doc_auto_cfg`
feature was subsumed by `doc_cfg`. This does overall looks like we're on
a path toward stabilization, which is great.

One problem here though is that a bunch of crates use the `cfg`
`docsrs` to enable `doc_auto_cfg`. So if we enable it, then it causes
those crates to emit hard errors. This is overall very annoying, and
I don't know how to unfuck things. So I changed the `cfg` knob to
`docsrs_jiff` which, doesn't quite provide a guarantee, but gets us
closer to being masters of our own destiny.

See also a similar change made to `regex`:
https://github.com/rust-lang/regex/pull/1305
2025-10-13 12:50:49 -04:00
Andrew Gallant
877d90a5f6
bench: tweak benchmark names
Some checks failed
ci / test-only-bundle (nightly, ubuntu-latest, nightly) (push) Has been cancelled
ci / test-core (macos, macos-latest, nightly) (push) Has been cancelled
ci / win-gnu (push) Has been cancelled
ci / msrv (push) Has been cancelled
ci / examples (push) Has been cancelled
ci / integrations (push) Has been cancelled
ci / time-zone-init (macos-latest) (push) Has been cancelled
ci / time-zone-init (ubuntu-24.04-arm) (push) Has been cancelled
ci / time-zone-init (ubuntu-latest) (push) Has been cancelled
ci / cross (aarch64-linux-android) (push) Has been cancelled
ci / cross (aarch64-unknown-linux-gnu) (push) Has been cancelled
ci / cross (i686-unknown-linux-gnu) (push) Has been cancelled
ci / cross (powerpc-unknown-linux-gnu) (push) Has been cancelled
ci / cross (powerpc64-unknown-linux-gnu) (push) Has been cancelled
ci / cross (s390x-unknown-linux-gnu) (push) Has been cancelled
ci / cross (x86_64-linux-android) (push) Has been cancelled
ci / riscv32imc-unknown-none-elf (push) Has been cancelled
ci / wasm32-wasip1 (push) Has been cancelled
ci / wasm32-unknown-emscripten (push) Has been cancelled
ci / wasm32-unknown-uknown (push) Has been cancelled
ci / rustfmt (push) Has been cancelled
ci / generated (push) Has been cancelled
ci / test-only-bundle (macos, macos-latest, nightly) (push) Has been cancelled
ci / test-core (nightly, ubuntu-latest, nightly) (push) Has been cancelled
ci / test-various-feature-combos (macos, macos-latest, nightly) (push) Has been cancelled
ci / test-various-feature-combos (nightly, ubuntu-latest, nightly) (push) Has been cancelled
ci / test-release (push) Has been cancelled
ci / test-doc (push) Has been cancelled
ci / test-bench (push) Has been cancelled
ci / win-msvc (push) Has been cancelled
It doesn't make sense to distinguish between a duration and a span in
the "construct timestamp from seconds" benchmark, so just use a more
generic name here.
2025-10-10 08:25:31 -04:00
Andrew Gallant
0315477648 fmt: fix panic bug in strptime when using %C
Some checks failed
ci / test-default (macos, macos-latest, stable) (push) Has been cancelled
ci / test-default (beta, ubuntu-latest, beta) (push) Has been cancelled
ci / test-core (macos, macos-latest, nightly) (push) Has been cancelled
ci / test-default (nightly, ubuntu-latest, nightly) (push) Has been cancelled
ci / test-default (stable, ubuntu-latest, stable) (push) Has been cancelled
ci / test-all (macos, macos-latest, nightly) (push) Has been cancelled
ci / test-all (nightly, ubuntu-latest, nightly) (push) Has been cancelled
ci / test-only-bundle (macos, macos-latest, nightly) (push) Has been cancelled
ci / test-only-bundle (nightly, ubuntu-latest, nightly) (push) Has been cancelled
ci / test-various-feature-combos (macos, macos-latest, nightly) (push) Has been cancelled
ci / test-various-feature-combos (nightly, ubuntu-latest, nightly) (push) Has been cancelled
ci / test-release (push) Has been cancelled
ci / test-doc (push) Has been cancelled
ci / test-bench (push) Has been cancelled
ci / test-miri (push) Has been cancelled
ci / win-msvc (push) Has been cancelled
ci / win-gnu (push) Has been cancelled
ci / cross (aarch64-linux-android) (push) Has been cancelled
ci / cross (aarch64-unknown-linux-gnu) (push) Has been cancelled
ci / cross (i686-unknown-linux-gnu) (push) Has been cancelled
ci / cross (powerpc-unknown-linux-gnu) (push) Has been cancelled
ci / cross (powerpc64-unknown-linux-gnu) (push) Has been cancelled
ci / cross (x86_64-linux-android) (push) Has been cancelled
ci / cross (s390x-unknown-linux-gnu) (push) Has been cancelled
ci / riscv32imc-unknown-none-elf (push) Has been cancelled
ci / wasm32-wasip1 (push) Has been cancelled
ci / wasm32-unknown-emscripten (push) Has been cancelled
ci / wasm32-unknown-uknown (push) Has been cancelled
ci / rustfmt (push) Has been cancelled
ci / generated (push) Has been cancelled
The code previously assumed that `%C` could never parse more than 2
digits. I believe this restriction was relaxed at some point, but the
assumption was never revisited in this part of the code.

This fixes the panic by forcefully restricting the absolute value of the
parsed century to be in the range `0..=99`.

Fixes #426
2025-10-08 19:34:17 -04:00
Andrew Gallant
5dcabd788d tz: fix panicking bug in TZif parser
Some checks are pending
ci / test-only-bundle (macos, macos-latest, nightly) (push) Waiting to run
ci / test-only-bundle (nightly, ubuntu-latest, nightly) (push) Waiting to run
ci / test-core (macos, macos-latest, nightly) (push) Waiting to run
ci / test-core (nightly, ubuntu-latest, nightly) (push) Waiting to run
ci / test-various-feature-combos (macos, macos-latest, nightly) (push) Waiting to run
ci / win-msvc (push) Waiting to run
ci / win-gnu (push) Waiting to run
ci / msrv (push) Waiting to run
ci / examples (push) Waiting to run
ci / integrations (push) Waiting to run
ci / time-zone-init (macos-latest) (push) Waiting to run
ci / time-zone-init (ubuntu-24.04-arm) (push) Waiting to run
ci / time-zone-init (ubuntu-latest) (push) Waiting to run
ci / test-default (nightly, ubuntu-latest, nightly) (push) Waiting to run
ci / test-default (stable, ubuntu-latest, stable) (push) Waiting to run
ci / test-all (macos, macos-latest, nightly) (push) Waiting to run
ci / test-all (nightly, ubuntu-latest, nightly) (push) Waiting to run
ci / cross (aarch64-linux-android) (push) Waiting to run
ci / cross (aarch64-unknown-linux-gnu) (push) Waiting to run
ci / cross (i686-unknown-linux-gnu) (push) Waiting to run
ci / cross (powerpc-unknown-linux-gnu) (push) Waiting to run
ci / cross (powerpc64-unknown-linux-gnu) (push) Waiting to run
ci / cross (s390x-unknown-linux-gnu) (push) Waiting to run
ci / cross (x86_64-linux-android) (push) Waiting to run
ci / riscv32imc-unknown-none-elf (push) Waiting to run
ci / wasm32-wasip1 (push) Waiting to run
ci / wasm32-unknown-emscripten (push) Waiting to run
ci / wasm32-unknown-uknown (push) Waiting to run
ci / rustfmt (push) Waiting to run
ci / generated (push) Waiting to run
This can only happen when malformed TZif data is given. Generally
speaking, Jiff treats TZif data as untrusted and promises not to panic
when given malformed data. So this is something that ought to be fixed.
However, it's rare to use untrusted TZif data in practice.

In this specific case, we were assuming that the time zone designation
list was always terminated by NUL.

Fixes #423
2025-10-08 12:18:36 -04:00
Andrew Gallant
bc00a543a2
strtime: remove incorrect docs on BrokenDownTime::set_meridiem
Some checks failed
ci / test-core (macos, macos-latest, nightly) (push) Has been cancelled
ci / test-core (nightly, ubuntu-latest, nightly) (push) Has been cancelled
ci / test-various-feature-combos (macos, macos-latest, nightly) (push) Has been cancelled
ci / test-various-feature-combos (nightly, ubuntu-latest, nightly) (push) Has been cancelled
ci / test-release (push) Has been cancelled
ci / test-doc (push) Has been cancelled
ci / test-bench (push) Has been cancelled
ci / test-miri (push) Has been cancelled
ci / win-msvc (push) Has been cancelled
ci / win-gnu (push) Has been cancelled
ci / integrations (push) Has been cancelled
ci / time-zone-init (ubuntu-24.04-arm) (push) Has been cancelled
ci / cross (aarch64-linux-android) (push) Has been cancelled
ci / cross (i686-unknown-linux-gnu) (push) Has been cancelled
ci / cross (powerpc-unknown-linux-gnu) (push) Has been cancelled
ci / msrv (push) Has been cancelled
ci / examples (push) Has been cancelled
ci / time-zone-init (macos-latest) (push) Has been cancelled
ci / time-zone-init (ubuntu-latest) (push) Has been cancelled
ci / time-zone-init (windows-latest) (push) Has been cancelled
ci / cross (aarch64-unknown-linux-gnu) (push) Has been cancelled
ci / cross (powerpc64-unknown-linux-gnu) (push) Has been cancelled
ci / cross (s390x-unknown-linux-gnu) (push) Has been cancelled
ci / cross (x86_64-linux-android) (push) Has been cancelled
ci / riscv32imc-unknown-none-elf (push) Has been cancelled
ci / wasm32-wasip1 (push) Has been cancelled
ci / wasm32-unknown-emscripten (push) Has been cancelled
ci / wasm32-unknown-uknown (push) Has been cancelled
ci / rustfmt (push) Has been cancelled
ci / generated (push) Has been cancelled
I missed this in the previous commit. Oops.
2025-09-28 09:35:18 -04:00
Tiffany Bennett
99545c6f88 strtime: add BrokenDownTime::set_meridiem
I'm not sure why I didn't add this originally. There is some confusion
around what happens when the hour value is inconsistent with the
meridiem, but that could already happen when parsing. And in that case,
the meridiem takes precedence over the parsed hour value. So we do the
same when formatting too.

Ref https://github.com/tiffany352/rink-rs/pull/210#pullrequestreview-3063953337

PR #397
2025-09-28 09:32:33 -04:00
Andrew Gallant
962edee175 shared: fix some panics in POSIX time zone parsing caught by a fuzzer
The first one here was pretty embarrassing: the parser panicked on the
empty string.

The others were a bit subtler and had to do with incorrect construction
of error messages. Arguably, more tests for the error cases here ought
to be added.

Fixes #407
2025-09-25 20:56:19 -04:00
HBJ
69c87b8688
fmt/strtime: handle EOF after colons in a directive
Fixes #410
2025-09-25 19:31:34 -04:00
Paolo Barbolini
0cac480e2d
serde: switch serde dependency to serde_core
serde_core has just been released. Crates that don't depend on serde derive macros should use it instead of serde, as it speeds up compile times by having the build for the crate itself be independent from serde-derive (in case it were to be enabled by some other crate). See the serde_core docs for more info.

On my Ryzen 5 5500U, building this repo with cargo build --release --features serde went from 10.83s to 8.76s.
2025-09-25 15:24:32 -04:00