BurntSushi/jiff
 Watch   
 Star   
 Fork   
2025-02-11 10:38:24
jiff

0.2.0

Sponsorship is appreciated!

This is a new semver incompatible release of Jiff. It contains several breaking changes. I expect most users of Jiff to be able to upgrade without any changes. The fundamental API organization of Jiff has not changed.

In case you haven't heard of it before, Jiff is a relatively new datetime library for Rust. Jiff takes enormous inspiration from Temporal. 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's overall goal is to guide you into the pit of success and make it harder to write buggy code for handling datetimes.

Some of the highlights of this release include reducing footguns and better ecosystem integration.

For reducing footguns, APIs on Span will no longer implicitly assume that days are always 24 hours long. And Span no longer implements PartialEq or Eq (instead favoring span.fieldwise() to create a value that supports naive fieldwise comparison). Moreover, when using TimeZone::system() (perhaps via Zoned::now()), if the system time zone could not be detected, then a special Etc/Unknown time zone will be used instead. This avoids erroring, but also surfaces itself to make it clearer that something has (perhaps) gone wrong.

As for ecosystem integration, this release coincides with the publication of the jiff-icu, jiff-sqlx and jiff-diesel crates. jiff-icu integrates with the ICU4X project, and is now the recommended way to use Jiff to work with non-Gregorian calendars or to localize datetimes for end users. jiff-sqlx and jiff-diesel provide wrapper types that implement the necessary traits to make it ergonomic to store and retrieve Jiff values in a database using SQLx or Diesel, respectively.

Unless something unexpected happens, my plan is for the next breaking change release to be Jiff 1.0 in about 6 months. Once Jiff 1.0 is out, I plan to commit to it indefinitely.

BREAKING CHANGES:

This is an exhaustive list of breaking changes. Changes with the bolded RUNTIME prefix are changes that will not be caught by the Rust compiler. That is, they are changes in runtime behavior.

  • #28: The deprecated intz routines on Zoned, Timestamp, civil::DateTime and civil::Date have been removed. You can use in_tz instead. This change was made because many found the name intz to be unclear.
  • #32: The PartialEq and Eq trait implementations on Span have been removed. Ideally these shouldn't have been used, but if you do need them, please use Span::fieldwise to create a SpanFieldwise, which does have the PartialEq and Eq traits implemented. These were removed on Span itself because they made it very easy to commit subtle bugs.
  • #36: Turn panics during Timestamp::saturing_add into errors. Callers adding spans that are known to contain units of hours or smaller are guaranteed that this will not return an error.
  • RUNTIME #48: On Span APIs, days are no longer silently assumed to always be 24 hours when a relative datetime is not provided. Instead, to perform operations on units of days or bigger, callers must either provide a relative date or opt into invariant 24-hour days with SpanRelativeTo::days_are_24_hours. Shortcuts have been added to the span builders. For example, SpanTotal::days_are_24_hours.
  • RUNTIME #147: Change the behavior of the deprecated %V conversion specifier in jiff::fmt::strtime from formatting an IANA time zone identifier to formatting an ISO 8601 week number. To format an IANA time zone identifier, use %Q or %:Q (which were introduced in jiff 0.1).
  • RUNTIME #212: When parsing into a Zoned with a civil time corresponding to a gap, we treat all offsets as invalid and return an error. Previously, we would accept the offset as given. This brings us into line with Temporal's behavior. For example, previously Jiff accepted 2006-04-02T02:30-05[America/Indiana/Vevay] but will now return an error. This is desirable for cases where a datetime in the future is serialized before a change in the daylight saving time rules. For more examples, see jiff::fmt::temporal::DateTimeParser::offset_conflict for details on how to change Jiff's default behavior. This behavior change also applies to tz::OffsetConflict::PreferOffset.
  • RUNTIME #213: Tweak the semantics of tz::TimeZoneDatabase so that it only initializes one internal tzdb instead of trying to find as many as possible. It is unlikely that you'll be impacted by this change, but it's meant to make the semantics be a bit more sensible. (In jiff 0.1, it was in theory possible for one tz lookup to succeed in the system zoneinfo and then another tz lookup to fail in zoneinfo but succeed automatically via the bundled copy. But this seems confusing and possibly not desirable. Hence the change.)
  • #218: In order to make naming a little more consistent between Zoned and civil::Date, the civil::Date::to_iso_week_date and civil::ISOWeekDate::to_date APIs were renamed to civil::Date::iso_week_date and civil::ISOWeekDate::date.
  • #220: Remove Span::to_duration for converting a Span to a std::time::Duration and rename Span::to_jiff_duration to Span::to_duration. This prioritizes SignedDuration as the "primary" non-calendar duration type in Jiff. And makes it more consistent with APIs like Zoned::duration_since. For non-calendar spans, the TryFrom<Span> for std::time::Duration still exists. For calendar durations, use Span::to_duration and then convert the SignedDuration to std::time::Duration. Additionally, Timestamp::from_jiff_duration and Timestamp::as_jiff_duration were renamed to Timestamp::from_duration and Timestamp::as_duration, respectively. The old deprecated routines on the unsigned std::time::Duration have been removed.
  • #221: Change the type of the value yielded by the jiff::tz::TimeZoneNameIter iterator from String to jiff::tz::TimeZoneName. This opaque type is more API evolution friendly. To access the string, either use TimeZoneName's Display trait implementation, or its as_str method.
  • #222: Split TimeZone::to_offset into two methods. One that just returns the offset, and another, TimeZone::to_offset_info, which includes the offset, DST status and time zone abbreviation. The extra info is rarely needed and is sometimes more costly to compute. Also, make the lifetime of the time zone abbreviation returned by TimeZoneTransition::abbreviation tied to the transition instead of the time zone (for future API flexibility, likely in core-only environments). This change was overall motivated by wanting to do less work in the common case (where we only need the offset), and for reducing the size of a TimeZone considerably in core-only environments. Callers previously using TimeZone::to_offset to get DST status and time zone abbreviation should now use TimeZone::to_offset_info.
  • RUNTIME #230: When TimeZone::system() cannot find a system configured time zone, jiff 0.1 would automatically fall back to TimeZone::UTC (with a WARN-level log message). In jiff 0.2, the fall back is now to TimeZone::unknown(), which has a special Etc/Unknown identifier (as specified by Unicode and reserved by the IANA time zone database). The fallback otherwise still behaves as if it were TimeZone::UTC. This helps surface error conditions related to finding the system time zone without causing unrecoverable failure.

Enhancements:

  • #136: When the special SpanRelativeTo::days_are_24_hours() marker is used, weeks will also be treated as invariant. That is, seven 24-hour days. In all cases, working with years and months still requires a relative date.
  • #228: It is now possible to forcefully use a bundled copy of the IANA time zone database without relying on disabling crate features. This can be done by enabling the tzdb-bundle-always crate feature and explicitly creating a jiff::tz::TimeZoneDatabase::bundled() database. Once in hand, you must use APIs like TimeZoneDatabase::get to create a TimeZone and avoid any APIs that implicitly use the global time zone database (like Timestamp::in_tz or even Zoned::from_str).
  • #238: Add integration with the ICU4X project via the jiff-icu crate. jiff-icu provides traits for easily converting between datetime types defined in Jiff and datetime types defined in ICU4X.
  • #240: Add integration with the SQLx project via the jiff-sqlx crate. jiff-sqlx provides wrapper types that implement the necessary traits in SQLx for reasonably ergonomic integration. This includes PostgreSQL and SQLite support, but not MySQL support. (It's not clear if it's possible at present to provide MySQL supprot fro SQLx for datetime types outside of SQLx itself.)
  • #241: Add integration with the Diesel project via the jiff-diesel crate. jiff-diesel provides wrapper types that implement the necessary traits in Diesel for reasonably ergonomic integration. This includes MySQL, PostgreSQL and SQLite support.