A datetime library for Rust that encourages you to jump into the pit of success.
Find a file
Andrew Gallant c3ad95044a
error: try to reduce amount of codegen by forcefully unlining error constructors
I had tried this several weeks ago, but recent exploration in #373
prompted me to revisit it. Indeed, `cargo llvm-lines` reveals that Jiff
is emitting a fair bit of code to LLVM just due to its error values. I
don't know how much of this is inherent to Jiff's attention to good
error messages or whether it's tied to how I've gone about it.

With that said... This isn't a pareto distribution. It's not like Jiff's
error handling is contributing to 80% of Jiff's LLVM lines or something.
It's just the biggest chunk. But that chunk seems to be around 11% or
so.

This PR tries to reduce that chunk, mostly by being a little more
careful about which error constructors are inlined and which aren't.
Basically, we want the error *branch* to be inlined into the calling
code (because that's likely a critical path), but we want everything
within the branch to be a call to a function that is ideally not
duplicated too much. I think there's a limit to how well we can do here,
but this PR does seem to improve things *without* runtime regressions.

Here's the first ~30% of where Jiff is emitting LLVM lines (as run from
the root of Jiff's repository) on current `master`:

```
  Lines                 Copies              Function name
  -----                 ------              -------------
  203564                5977                (TOTAL)
   10182 (5.0%,  5.0%)    86 (1.4%,  1.4%)  <jiff::error::Error as jiff::error::ErrorContext>::with_context
    5688 (2.8%,  7.8%)   204 (3.4%,  4.9%)  core::result::Result<T,E>::map_err
    3801 (1.9%,  9.7%)   145 (2.4%,  7.3%)  <core::result::Result<T,E> as core::ops::try_trait::Try>::branch
    2837 (1.4%, 11.1%)   116 (1.9%,  9.2%)  core::option::Option<T>::ok_or_else
    2120 (1.0%, 12.1%)     2 (0.0%,  9.3%)  jiff::fmt::friendly:🖨️:SpanPrinter::print_duration_designators
    1822 (0.9%, 13.0%)     2 (0.0%,  9.3%)  jiff::fmt::temporal:🖨️:SpanPrinter::print_span
    1658 (0.8%, 13.8%)     1 (0.0%,  9.3%)  jiff::fmt::strtime::parse::Parser::parse
    1652 (0.8%, 14.6%)     1 (0.0%,  9.3%)  jiff::fmt::strtime::format::Formatter<W,L>::format_one
    1548 (0.8%, 15.4%)     6 (0.1%,  9.4%)  jiff::fmt::temporal:🖨️:DateTimePrinter::print_time
    1312 (0.6%, 16.0%)   110 (1.8%, 11.3%)  <core::result::Result<T,F> as core::ops::try_trait::FromResidual<core::result::Result<core::convert::Infallible,E>>>::from_residual
    1260 (0.6%, 16.6%)     6 (0.1%, 11.4%)  jiff::fmt::temporal:🖨️:DateTimePrinter::print_date
    1219 (0.6%, 17.2%)    47 (0.8%, 12.1%)  core::option::Option<T>::map
    1160 (0.6%, 17.8%)    22 (0.4%, 12.5%)  core::option::Option<T>::map_or
    1071 (0.5%, 18.3%)    28 (0.5%, 13.0%)  core::result::Result<T,E>::unwrap
     997 (0.5%, 18.8%)    21 (0.4%, 13.3%)  core::option::Option<T>::or_else
     986 (0.5%, 19.3%)     1 (0.0%, 13.4%)  jiff::span::Span::from_invariant_nanoseconds
     976 (0.5%, 19.8%)    16 (0.3%, 13.6%)  <jiff::util::rangeint::RangedDebug<_,_> as core::fmt::Debug>::fmt
     920 (0.5%, 20.2%)    10 (0.2%, 13.8%)  <jiff::util::rangeint::ri32<_,_> as jiff::util::rangeint::RFrom<jiff::util::rangeint::ri64<_,_>>>::rfrom
     920 (0.5%, 20.7%)     4 (0.1%, 13.9%)  jiff::fmt::temporal:🖨️:DateTimePrinter::print_offset_rounded
     912 (0.4%, 21.1%)     6 (0.1%, 14.0%)  jiff::fmt::friendly:🖨️:DesignatorWriter<W>::write
     890 (0.4%, 21.6%)     2 (0.0%, 14.0%)  jiff::fmt::temporal:🖨️:SpanPrinter::print_duration
     840 (0.4%, 22.0%)    12 (0.2%, 14.2%)  jiff::util::rangeint::ri8<_,_>::get
     828 (0.4%, 22.4%)     6 (0.1%, 14.3%)  core::slice::<impl [T]>::binary_search_by
     819 (0.4%, 22.8%)    32 (0.5%, 14.8%)  core::result::Result<T,E>::unwrap_or_else
     802 (0.4%, 23.2%)     2 (0.0%, 14.9%)  jiff::fmt::friendly:🖨️:SpanPrinter::print_span_hms
     777 (0.4%, 23.6%)    10 (0.2%, 15.0%)  jiff::util::rangeint::Composite<T>::map
     758 (0.4%, 24.0%)     2 (0.0%, 15.1%)  jiff::fmt::friendly:🖨️:SpanPrinter::print_duration_hms
     744 (0.4%, 24.3%)     8 (0.1%, 15.2%)  core::array::try_from_fn_erased
     744 (0.4%, 24.7%)     2 (0.0%, 15.2%)  jiff::fmt::temporal:🖨️:DateTimePrinter::print_pieces
     720 (0.4%, 25.0%)     2 (0.0%, 15.3%)  jiff::fmt::friendly:🖨️:SpanPrinter::print_span_designators_non_fraction
     700 (0.3%, 25.4%)    10 (0.2%, 15.4%)  <core::iter::adapters::zip::Zip<A,B> as core::iter::adapters::zip::ZipImpl<A,B>>::next
     700 (0.3%, 25.7%)     7 (0.1%, 15.5%)  <jiff::util::rangeint::ri8<_,_> as jiff::util::rangeint::RFrom<jiff::util::rangeint::ri64<_,_>>>::rfrom
     682 (0.3%, 26.1%)     6 (0.1%, 15.6%)  jiff::fmt::strtime::format::<impl jiff::fmt::strtime::Extension>::write_int
     660 (0.3%, 26.4%)    10 (0.2%, 15.8%)  <core::iter::adapters::enumerate::Enumerate<I> as core::iter::traits::iterator::Iterator>::next
     659 (0.3%, 26.7%)     1 (0.0%, 15.8%)  jiff::fmt::rfc2822::DateTimePrinter::print_civil_with_offset
     600 (0.3%, 27.0%)     6 (0.1%, 15.9%)  <jiff::util::rangeint::ri8<_,_> as jiff::util::rangeint::RFrom<jiff::util::rangeint::ri32<_,_>>>::rfrom
     588 (0.3%, 27.3%)    12 (0.2%, 16.1%)  jiff::util::rangeint::ri8<_,_>::try_new
     588 (0.3%, 27.6%)     1 (0.0%, 16.1%)  jiff::tz::db::zoneinfo::inner::walk
     584 (0.3%, 27.9%)    86 (1.4%, 17.6%)  <core::result::Result<T,jiff::error::Error> as jiff::error::ErrorContext>::with_context::{{closure}}
     583 (0.3%, 28.2%)     1 (0.0%, 17.6%)  jiff::civil:📅:DateDifference::since_with_largest_unit
     581 (0.3%, 28.4%)    11 (0.2%, 17.8%)  jiff::error::RangeError::new
     574 (0.3%, 28.7%)     2 (0.0%, 17.8%)  core::slice::sort::stable::quicksort::stable_partition
     552 (0.3%, 29.0%)     2 (0.0%, 17.9%)  core::str::pattern::TwoWaySearcher::next_back
     545 (0.3%, 29.3%)    97 (1.6%, 19.5%)  <T as jiff::util::rangeint::RInto<U>>::rinto
     544 (0.3%, 29.5%)     2 (0.0%, 19.5%)  jiff::fmt::strtime::format::write_offset
     536 (0.3%, 29.8%)     4 (0.1%, 19.6%)  jiff::fmt::temporal:🖨️:DateTimePrinter::print_datetime
```

Other than error handling, it doesn't look like there is any one thing
that is contributing the most here. That means that I think real
improvements here are probably going to require combing through these
and ensuring that the number of copies of each function is as small as
it can be.

This PR does decrease the number of LLVM lines, but only marginally:

```
  Lines                 Copies              Function name
  -----                 ------              -------------
  192748                2457                (TOTAL)
    3978 (2.1%,  2.1%)     1 (0.0%,  0.0%)  jiff::fmt::strtime::format::Formatter<W,L>::format_one
    3785 (2.0%,  4.0%)     1 (0.0%,  0.1%)  jiff::fmt::strtime::parse::Parser::parse
    3600 (1.9%,  5.9%)     2 (0.1%,  0.2%)  jiff::fmt::temporal:🖨️:SpanPrinter::print_span
    3340 (1.7%,  7.6%)     2 (0.1%,  0.2%)  jiff::fmt::friendly:🖨️:SpanPrinter::print_duration_designators
    3250 (1.7%,  9.3%)    86 (3.5%,  3.7%)  <core::result::Result<T,jiff::error::Error> as jiff::error::ErrorContext>::with_context::{{closure}}
    2910 (1.5%, 10.8%)     6 (0.2%,  4.0%)  jiff::fmt::temporal:🖨️:DateTimePrinter::print_time
    2190 (1.1%, 12.0%)     1 (0.0%,  4.0%)  jiff::span::Span::from_invariant_nanoseconds
    2166 (1.1%, 13.1%)     6 (0.2%,  4.3%)  jiff::fmt::temporal:🖨️:DateTimePrinter::print_date
    1760 (0.9%, 14.0%)     2 (0.1%,  4.4%)  jiff::fmt::temporal:🖨️:SpanPrinter::print_duration
    1588 (0.8%, 14.8%)     2 (0.1%,  4.4%)  jiff::fmt::friendly:🖨️:SpanPrinter::print_span_hms
    1450 (0.8%, 15.6%)     2 (0.1%,  4.5%)  jiff::fmt::friendly:🖨️:SpanPrinter::print_span_designators_non_fraction
    1432 (0.7%, 16.3%)     4 (0.2%,  4.7%)  jiff::fmt::temporal:🖨️:DateTimePrinter::print_offset_rounded
    1398 (0.7%, 17.0%)     2 (0.1%,  4.8%)  jiff::fmt::temporal:🖨️:DateTimePrinter::print_pieces
    1368 (0.7%, 17.8%)     6 (0.2%,  5.0%)  jiff::fmt::friendly:🖨️:DesignatorWriter<W>::write
    1364 (0.7%, 18.5%)     2 (0.1%,  5.1%)  jiff::fmt::friendly:🖨️:SpanPrinter::print_duration_hms
    1248 (0.6%, 19.1%)    16 (0.7%,  5.7%)  <jiff::util::rangeint::RangedDebug<_,_> as core::fmt::Debug>::fmt
    1243 (0.6%, 19.8%)     1 (0.0%,  5.8%)  jiff::fmt::rfc2822::DateTimePrinter::print_civil_with_offset
    1222 (0.6%, 20.4%)    13 (0.5%,  6.3%)  jiff::util::rangeint::ri8<_,_>::new
    1108 (0.6%, 21.0%)    28 (1.1%,  7.4%)  core::result::Result<T,E>::unwrap
    1097 (0.6%, 21.5%)     1 (0.0%,  7.5%)  jiff::shared::tzif::Header::parse
    1086 (0.6%, 22.1%)    22 (0.9%,  8.4%)  core::option::Option<T>::map_or
     975 (0.5%, 22.6%)    21 (0.9%,  9.2%)  core::option::Option<T>::or_else
     970 (0.5%, 23.1%)     1 (0.0%,  9.3%)  jiff::fmt::rfc2822::DateTimePrinter::print_civil_always_utc
     923 (0.5%, 23.6%)     1 (0.0%,  9.3%)  jiff::fmt::offset::Parser::parse_numeric
     919 (0.5%, 24.1%)     1 (0.0%,  9.4%)  jiff::zoned::ZonedDifference::until_with_largest_unit
     884 (0.5%, 24.5%)     2 (0.1%,  9.4%)  jiff::tz::concatenated::Header::read
     842 (0.4%, 25.0%)     2 (0.1%,  9.5%)  jiff::fmt::strtime::format::write_offset
     822 (0.4%, 25.4%)     6 (0.2%,  9.8%)  core::slice::<impl [T]>::binary_search_by
     816 (0.4%, 25.8%)     6 (0.2%, 10.0%)  jiff::fmt::strtime::format::<impl jiff::fmt::strtime::Extension>::write_int
     796 (0.4%, 26.2%)     1 (0.0%, 10.1%)  jiff::shared::tzif::<impl jiff::shared::Tzif<alloc::string::String,jiff::shared::util::array_str::ArrayStr<30_usize>,alloc::vec::Vec<jiff::shared::TzifLocalTimeType>,alloc::vec::Vec<i64>,alloc::vec::Vec<jiff::shared::TzifDateTime>,alloc::vec::Vec<jiff::shared::TzifDateTime>,alloc::vec::Vec<jiff::shared::TzifTransitionInfo>>>::parse64
     792 (0.4%, 26.6%)    22 (0.9%, 10.9%)  <core::result::Result<T,jiff::error::Error> as jiff::error::ErrorContext>::context::{{closure}}
     784 (0.4%, 27.0%)     4 (0.2%, 11.1%)  jiff::fmt::temporal:🖨️:DateTimePrinter::print_datetime
     773 (0.4%, 27.4%)     2 (0.1%, 11.2%)  jiff::tz::offset::OffsetConflict::resolve_via_reject
     758 (0.4%, 27.8%)     2 (0.1%, 11.3%)  jiff::shared::posix::<impl jiff::shared::PosixTimeZone<ABBREV>>::to_ambiguous_kind
     736 (0.4%, 28.2%)     4 (0.2%, 11.4%)  jiff::fmt::friendly:🖨️:FractionalPrinter::print
     687 (0.4%, 28.6%)     1 (0.0%, 11.5%)  jiff::tz::db::zoneinfo::inner::walk
     680 (0.4%, 28.9%)     1 (0.0%, 11.5%)  jiff::shared::tzif::<impl jiff::shared::Tzif<alloc::string::String,jiff::shared::util::array_str::ArrayStr<30_usize>,alloc::vec::Vec<jiff::shared::TzifLocalTimeType>,alloc::vec::Vec<i64>,alloc::vec::Vec<jiff::shared::TzifDateTime>,alloc::vec::Vec<jiff::shared::TzifDateTime>,alloc::vec::Vec<jiff::shared::TzifTransitionInfo>>>::parse_time_zone_designations
     654 (0.3%, 29.3%)     2 (0.1%, 11.6%)  jiff::shared::posix::<impl jiff::shared::PosixTimeZone<ABBREV>>::previous_transition
     652 (0.3%, 29.6%)     2 (0.1%, 11.7%)  jiff::shared::posix::<impl jiff::shared::PosixTimeZone<ABBREV>>::next_transition
     650 (0.3%, 29.9%)     1 (0.0%, 11.7%)  jiff::tz::system::get_env_tz
```

I wonder if my approach to error handling with just using strings
everywhere is hurting things. The main alternative would be structured
errors everywhere. But there are _so many_ error messages that writing
out structured definitions for each is terrifying to me (even if I was
willing to use something like `thiserror` to reduce the boiler plate
aspect of it).

In terms of actual compile times, this _does_ seem to have a positive
impact on compile times. My test setup here was to:

1. Add `[patch.crates-io]` with a `jiff` entry to
   [Biff's](https://github.com/BurntSushi/biff) `Cargo.toml`.
2. Run
   `touch path/to/jiff/src/lib.rs && touch src/main.rs && time cargo build --release`
   from the root of Biff's repository.

The timings I get are wildly variable. But the minimum time I got with
this PR was 5.8s while the minimum time I've seen for Jiff master is
6.3s. This is on an otherwise quiet machine with the CPU governor set
to `performance`.

Finally, running the benchmarks has some noise, but there are no obvious
regressions:

```
$ critcmp base zchange3 -f '/jiff$' -t 5
group                                                    base                                   zchange3
-----                                                    ----                                   --------
civil_datetime/to_timestamp_tzdb_lookup/zoneinfo/jiff    1.00     43.5±0.27ns        ? ?/sec    1.24     54.1±0.23ns        ? ?/sec
date/add_days/one/duration/jiff                          1.00      5.2±0.05ns        ? ?/sec    1.08      5.6±0.04ns        ? ?/sec
date/add_days/one/span/jiff                              1.00      9.5±0.09ns        ? ?/sec    1.06     10.0±0.08ns        ? ?/sec
date/add_years_months_days/jiff                          1.08     24.7±0.20ns        ? ?/sec    1.00     22.8±0.16ns        ? ?/sec
parse/friendly/long/span/jiff                            1.06    122.8±0.18ns        ? ?/sec    1.00    115.9±0.27ns        ? ?/sec
parse/friendly/longer/span/jiff                          1.05    124.2±0.29ns        ? ?/sec    1.00    118.0±0.79ns        ? ?/sec
parse/friendly/medium/span/jiff                          1.05     67.8±0.22ns        ? ?/sec    1.00     64.5±0.26ns        ? ?/sec
parse/friendly/short/duration/jiff                       1.17     16.6±0.28ns        ? ?/sec    1.00     14.2±0.34ns        ? ?/sec
parse/rfc2822/jiff                                       1.25     29.4±0.31ns        ? ?/sec    1.00     23.5±0.26ns        ? ?/sec
parse/strptime/oneshot/jiff                              1.11     74.3±0.63ns        ? ?/sec    1.00     67.0±0.48ns        ? ?/sec
timestamp/every_hour_in_week/series/jiff                 1.33    143.8±0.70ns        ? ?/sec    1.00    107.7±0.61ns        ? ?/sec
tz/posix_datetime_to_offset/jiff                         1.00     31.0±0.24ns        ? ?/sec    1.05     32.5±0.20ns        ? ?/sec
zoned/fixed_offset_to_timestamp/jiff                     1.25      0.4±0.00ns        ? ?/sec    1.00      0.3±0.00ns        ? ?/sec
```

Given the reduction in LLVM times, the seeming reduction in compile
times and the lack of obvious runtime regressions, I think this PR is a
strict improvement.

Ref #373
2025-05-18 08:42:11 -04:00
.devcontainer github: add devcontainer.json for development (#79) 2024-08-06 14:47:36 -04:00
.github tz: fallback to Etc/Unknown when TZ is set to an invalid value 2025-05-17 11:02:57 -04:00
.vim vim: remove most linked projects 2025-04-11 20:30:53 -04:00
bench bench: add strftime benchmark 2025-04-28 12:12:44 -04:00
crates jiff-icu: bump ICU4X to 2.0.0 2025-05-08 16:52:55 -04:00
examples tz: fallback to Etc/Unknown when TZ is set to an invalid value 2025-05-17 11:02:57 -04:00
scripts tz: fallback to Etc/Unknown when TZ is set to an invalid value 2025-05-17 11:02:57 -04:00
src error: try to reduce amount of codegen by forcefully unlining error constructors 2025-05-18 08:42:11 -04:00
testprograms/invalid-tz-environment-variable tz: fallback to Etc/Unknown when TZ is set to an invalid value 2025-05-17 11:02:57 -04:00
tests ci: improve tzdb init times and tests 2025-05-09 17:33:22 -04:00
.gitignore cargo: restore sanity to iterative development 2025-04-10 20:54:30 -04:00
.rgignore first substantial commit 2024-07-21 20:15:13 -04:00
Cargo.toml ci: improve tzdb init times and tests 2025-05-09 17:33:22 -04:00
CHANGELOG.md tz: fallback to Etc/Unknown when TZ is set to an invalid value 2025-05-17 11:02:57 -04:00
COMPARE.md bench: make some small updates to benchmarks 2025-03-05 18:48:44 -05:00
COPYING initial commit 2024-02-17 13:33:45 -05:00
Cross.toml jiff: add robust WASM support 2024-07-30 17:16:37 -07:00
DESIGN.md doc: final touch-ups before 0.2.0 2025-02-10 21:25:29 -05:00
LICENSE-MIT initial commit 2024-02-17 13:33:45 -05:00
PLATFORM.md doc: some minor clean-ups 2025-05-05 20:33:34 -04:00
README.md doc: final touch-ups before 0.2.0 2025-02-10 21:25:29 -05:00
rustfmt.toml cargo: restore sanity to iterative development 2025-04-10 20:54:30 -04:00
UNLICENSE initial commit 2024-02-17 13:33:45 -05:00

Jiff

Jiff is a datetime library for Rust that encourages you to jump into the pit of success. The focus of this library is providing high level datetime primitives that are difficult to misuse and have reasonable performance. Jiff supports automatic and seamless integration with the Time Zone Database, DST aware arithmetic and rounding, formatting and parsing zone aware datetimes losslessly, opt-in Serde support and a whole lot more.

Jiff takes enormous inspiration from Temporal, which is a TC39 proposal to improve datetime handling in JavaScript.

Build status Crates.io Docs.rs

Dual-licensed under MIT or the UNLICENSE.

Documentation

Example

Here is a quick example that shows how to parse a typical RFC 3339 instant, convert it to a zone aware datetime, add a span of time and losslessly print it:

use jiff::{Timestamp, ToSpan};

fn main() -> Result<(), jiff::Error> {
    let time: Timestamp = "2024-07-11T01:14:00Z".parse()?;
    let zoned = time.in_tz("America/New_York")?.checked_add(1.month().hours(2))?;
    assert_eq!(zoned.to_string(), "2024-08-10T23:14:00-04:00[America/New_York]");
    // Or, if you want an RFC3339 formatted string:
    assert_eq!(zoned.timestamp().to_string(), "2024-08-11T03:14:00Z");
    Ok(())
}

There are many more examples in the documentation.

Usage

Jiff is on crates.io and can be used by adding jiff to your dependencies in your project's Cargo.toml. Or more simply, just run cargo add jiff.

Here is a complete example that creates a new Rust project, adds a dependency on jiff, creates the source code for a simple datetime program and then runs it.

First, create the project in a new directory:

$ cargo new jiff-example
$ cd jiff-example

Second, add a dependency on jiff:

$ cargo add jiff

Third, edit src/main.rs. Delete what's there and replace it with this:

use jiff::{Unit, Zoned};

fn main() -> Result<(), jiff::Error> {
    let now = Zoned::now().round(Unit::Second)?;
    println!("{now}");
    Ok(())
}

Fourth, run it with cargo run:

$ cargo run
   Compiling jiff v0.2.0 (/home/andrew/rust/jiff)
   Compiling jiff-play v0.2.0 (/home/andrew/tmp/scratch/rust/jiff-play)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.37s
     Running `target/debug/jiff-play`
2024-07-10T19:54:20-04:00[America/New_York]

The first time you run the program will show more output like above. But subsequent runs shouldn't have to re-compile the dependencies.

Crate features

Jiff has several crate features for customizing support for Rust's standard library, serde support and whether to embed a copy of the Time Zone Database into your binary.

The "crate features" section of the documentation lists the full set of supported features.

Future plans

With jiff 0.2 out about 6 months after the jiff 0.1 initial release, my plan remains roughly the same as it started. That is, I'd still like to get a jiff 1.0 release out this summer 2025 (in about 6 months) and then commit to it indefinitely. This plan may change if something critically wrong is found with the current API.

The purpose of this plan is to get Jiff to a 1.0 stable state as quickly as possible. The reason is so that others feel comfortable relying on Jiff as a public dependency that won't cause ecosystem churn.

Performance

The most important design goal of Jiff is to be a high level datetime library that makes it hard to do the wrong thing. Second to that is performance. Jiff should have reasonable performance, but there are likely areas in which it could improve. See the bench directory for benchmarks.

Note that performance is still an important goal. Some aspects of Jiff have had optimization attention paid to them, but many still have not. It is a goal to improve where we can, but performance will generally come second to API comprehension and correctness.

Platform support

The question of platform support in the context of datetime libraries comes up primarily in relation to time zone support. Specifically:

  • How should Jiff determine the time zone transitions for an IANA time zone identifier like Antarctica/Troll?
  • How should Jiff determine the default time zone for the current system?

Both of these require some level of platform interaction.

For discovering time zone transition data, Jiff relies on the IANA Time Zone Database. On Unix systems, this is usually found at /usr/share/zoneinfo, although it can be configured via the TZDIR environment variable (which Jiff respects). On Windows, Jiff will automatically embed a copy of the time zone database into the compiled library.

For discovering the system time zone, Jiff reads /etc/localtime on Unix. On Windows, Jiff reads the Windows-specific time zone identifier via GetDynamicTimeZoneInformation and then maps it to an IANA time zone identifier via Unicode's CLDR XML data.

I expect Jiff to grow more support for other platforms over time. Please file issues, although I will likely be reliant on contributor pull requests for more obscure platforms that aren't easy for me to test.

For more on platform support, see PLATFORM.md.

Dependencies

At time of writing, it is no accident that Jiff has zero dependencies on Unix. In general, my philosophy on adding new dependencies in an ecosystem crate like Jiff is very conservative. I consider there to be two primary use cases for adding new dependencies:

  1. When a dependency is practically required in order to interact with a platform. For example, windows-sys for discovering the system time zone on Windows.
  2. When a dependency is necessary for inter-operability. For example, serde. But even here, I expect to be conservative, where I'm generally only willing to depend on things that have fewer breaking change releases than Jiff.

A secondary use case for new dependencies is if Jiff gets split into multiple crates. I did a similar thing for the regex crate for very compelling reasons. It is possible that will happen with Jiff as well, although there are no plans for that. And in general, I expect the number of crates to stay small, if only to make keep maintenance lightweight. (Managing lots of semver API boundaries has a lot of overhead in my experience.)

Minimum Rust version policy

This crate's minimum supported rustc version is 1.70.0.

The policy is that the minimum Rust version required to use this crate can be increased in minor version updates. For example, if jiff 1.0 requires Rust 1.20.0, then jiff 1.0.z for all values of z will also require Rust 1.20.0 or newer. However, jiff 1.y for y > 0 may require a newer minimum version of Rust.