Skipping whitespace happens immediately before `input[0]`. But skipping
the whitespace could lead to `input` being empty.
We handle the empty case and add a regression test.
Fixes#359
Previously we were allowing this through since we didn't distinguish
between `-00:45` and `-00:45:00` when checking offset equality. In the
former case, we round the actual offset (which is `-00:44:30` in this
case), and if it matches the provided offset, we allow it. But in the
latter case, we *should* respect the precision specified in the string
and perform exact equality.
We fix this by just querying the parsed structure to see if a second
component was actually parsed or not. If it was, we do exact equality.
(For context, this is only an issue because Temporal, and also Jiff,
generally only support time zone offsets up to minute precision when
formatting. This reflects what RFC 3339 and RFC 9557 support. However,
we still support *parsing* offsets with sub-minute precision. To make
everything consistent and round-trip, we permit rounding as a means to
test offset equality when a time zone offset has sub-minute precision
but a parsed offset does not.)
Fixes#357
Previously, the documentation for `Display` trait implementations on
datetime types discussed precision, but omitted the default behavior.
This PR documents the default behavior and makes the docs for
`Timestamp`, `Zoned`, `civil::DateTime` and `civil::Time` a bit more
consistent.
Fixes#328
RFC2822 allows some unusual whitespace configurations
which weren't covered previously. In particular, these two cases
are now handled properly according to spec:
(1) Whitespace is allowed, but may also be completely omitted, on both
sides of the `,` following the weekday;
(2) Whitespace is allowed around the time separators (`:`).
Fixes#339
This is another (IMO) cursed API meant to provide some measure of
compatibility with GNU date: a mode that specifically ignores errors
when formatting datetimes using `jiff::fmt::strtime`.
For example, neither `%0` nor `%+` are valid conversion specifiers
supported by Jiff. By default, using those will result in an error. But
with the new lenient mode (which you need to opt into), no error will
occur and instead `%0` and `%+` just get written literally as-is in the
returned string.
This applies to other kinds of errors. For example, if you use `%z` with
a `BrokenDownTime` that doesn't contain an offset, then that would
normally result in an error. But in lenient mode, it just results in
`%z` being written literally.
The docs for this mode contain a strongly worded warning to avoid
enabling this. It's makes for a terrible user experience because it
squashes failures without so much as a peep. The *only* reason anyone
should enable it is for when strict compatibility with other software
is necessary.
Closes#350
These are also motivated by their presence in GNU date. They are
basically just different ways of printing offsets from UTC.
We do some light refactoring to DRY up the code a bit, and to make it a
little nicer to handle a variable number (up to a fixed size limit) of
`:` characters preceding a directive.
This is honestly just a giant clusterfuck (who thinks having `%z`,
`%:z`, `%::z` and `%:::z` is a nice user experience!?!?), but so is
`strptime`/`strftime` I guess. Oh well.
Closes#342
I originally didn't do this because I perceived the offset parsing in
`strptime` to be "simple," and I didn't want to complicate the Temporal
offset parser. But now that we seek to support `%::z` and `%:::z` in
`strptime`, it makes sense to DRY things up a bit.
This is also found in GNU date. It simply prints the quarter of the
year.
We don't bother with parsing. It can't be used to construct a date. The
only thing we could support is actually parsing a new dedicated quarter
field. It's not really clear if that's worth it. If someone has a use
case for it, I'd be open to adding it. (Since `BrokenDownTime` is
already enormous.)
Closes#341
This conversion specifier is supported by GNU date.
Thankfully this was pretty easy to do, as it's just an alias for `%f`,
which Jiff already supports.
Closes#344
Previously, this was not being special cased, which in turn read `UTC`
like any other time zone. But really, we should be returning
`TimeZone::UTC` when and if we know that the time zone is actually
`UTC`.
Fixes#346
This is mostly just using `#[inline]` in variouos spots and
specializing common code paths.
The most interesting change is that a `BrokenDownTime` now
contains a `Option<TimeZone>` instead of a time zone
abbreviation. It turns out that getting the time zone
abbreviation for a fixed offset time zone does some work
up-front to format the string. By just storing the time
zone, we can defer that work until we know we actually
need it.
Specifically, this permits customizing the %c, %r, %X and %x
conversion specifiers. (Which are also newly added in this commit.)
We also include a default behavior for these specifiers
(meant to match Unicode's `und` locale) as well as an opt-in
POSIX behavior (meant to match POSIX's `C` locale).
Some minor refactoring is also included here. It was too annoying
to split into its own commit.
I've finally relented and exposes a very restricted way
to build an `Error` value.
I was motivated to do this because there are some traits
in Jiff that use `jiff::Error` in their return types. Without
a constructor like this, it isn't possible for implementors
of that trait to provide their own error values.
This basically does what is necessary to get everything compiled and
tests passing.
We'll add on time zone and offset stuff in a subsequent commit.
Note that we now depend on `icu_calendar` and `icu_time` directly, with
the latter being optional (but enabled by default). In particular, one
can do useful things with just conversions to dates with `icu_calendar`.
But I expect most folks will want both.
Unfortunately, I had a typo, which meant it recognized Tueday instead
Tuesday.
This was covered by tests, but I missed the typo in the asserted test
output too.
Fixes#333
Only the actual value matters. By deriving `Hash`, it was including the
tracked min/max values, which is of course incorrect.
Note that this was only an issue in debug mode. In release mode, the
min/max values aren't compiled in, and so the `Hash` impl was correct.
Fixes#330
This adds an "alternate" Debug implementation for `SignedDuration`.
The alternate impl is a more "straight forward" representation of
a `SignedDuration`'s internals. That is, it just shows seconds and
nanoseconds (omitting zero components). I find this much easier to
read when reasoning about SignedDuration, since its internals and, to
an extent, its API, are defined in terms of its second and nanosecond
components.
This also resulted in a panic for an undocumented case, in debug mode, in
`SignedDuration::from_secs_f64`.
A similar fix has been applied to the `f32` case as well.
The problem was that if the fractional part of the floating point
duration rounded up to 1, then the nanosecond component would represent
a single full second. This case wasn't correctly accounted for.
Fixes#324
In practice, we do this because otherwise
`cfg_attr(feature = "perf-inline")` will throw a warning otherwise. And
that happens because we use these annotations in code in Jiff that is
shared (via copying) with `jiff-static`. So instead of just removing the
annotations, we add `perf-inline` as a feature to `jiff-static`.
For `jiff-static`, we disable it by default, since we don't really care
about that level of perf when doing datetime calculations at compile
time.
It looks like this was actually the root cause of what was causing a
rustc stunlock. Apparently every save in my editor causes `cargo check`
to run on *all* of the linked projects? That seems nuts... Sigh.
This apparently got out of date. And it was apparently not being
enforced in CI. And the destination directory used by `jiff-cli` was
outdated. So fix all of that here, including re-generation.
This is copied over from `regex`. Basically, when this is enabled (which
is the default), then a bunch of `inline(always)` annotations are
scattered in places (as motivated by micro-benchmarking). Otherwise,
these annotations are removed.
Specifically, an environment variable that is *set* to
the empty string.
This seems like odd behavior to me, but it's apparently
what both GNU and BSD tooling do. And since Jiff's
support for `TZ` is really about conforming to existing
convention, we just do what everyone else does.
PR #319