or [`FromStr`](std::str::FromStr) trait implementations for printing and parsing respectively. This module provides a "lower level" API for configuring the behavior of printing and parsing, including the ability to parse from byte strings (i.e., `&[u8]`). # Date and time format The specific format supported depends on what kind of type you're trying to parse into. Here are some examples to give a general idea: * `02:21:58` parses into a [`civil::Time`]. * `2020-08-21` parses into a [`civil::Date`]. * `2020-08-21T02:21:58` and `2020-08-21 02:21:58` both parse into a [`civil::DateTime`]. * `2020-08-21T02:21:58-04` parses into an [`Timestamp`]. * `2020-08-21T02:21:58-04[America/New_York]` parses into a [`Zoned`]. Smaller types can generally be parsed from strings representing a bigger type. For example, a `civil::Date` can be parsed from `2020-08-21T02:21:58`. As mentioned above, the datetime format supported by Jiff is a hybrid of the "best" parts of [RFC 3339], [RFC 9557] and [ISO 8601]. Generally speaking, [RFC 3339] and [RFC 9557] are supported in their entirety, but not all of ISO 8601 is. For example, `2024-06-16T10.5` is a valid ISO 8601 datetime, but isn't supported by Jiff. (Only fractional seconds are supported.) Some additional details worth noting: * Parsing `Zoned` values requires a datetime string with a time zone annotation like `[America/New_York]` or `[-07:00]`. If you need to parse a datetime without a time zone annotation (but with an offset), then you should parse it as an [`Timestamp`]. From there, it can be converted to a `Zoned` via [`Timestamp::to_zoned`]. * When parsing `Zoned` values, ambiguous datetimes are handled via the [`DateTimeParser::disambiguation`] configuration. By default, a "compatible" mode is used where the earlier time is selected in a backward transition, while the later time is selected in a forward transition. * When parsing `Zoned` values, conflicts between the offset and the time zone in the datetime string are handled via the [`DateTimeParser::offset_conflict`] configuration. By default, any inconsistency between the offset and the time zone results in a parse error. * When parsing civil types like `civil::DateTime`, it's always an error if the datetime string has a `Z` (Zulu) offset. It's an error since interpreting such strings as civil time is usually a bug. * In all cases, the `T` designator separating the date and time may be an ASCII space instead. The complete datetime format supported is described by the [Temporal ISO 8601 grammar]. # Span format To a first approximation, the span format supported roughly corresponds to this regular expression: ```text P(\d+y)?(\d+m)?(\d+w)?(\d+d)?(T(\d+h)?(\d+m)?(\d+s)?)? ``` But there are some details not easily captured by a simple regular expression: * At least one unit must be specified. To write a zero span, specify `0` for any unit. For example, `P0d` and `PT0s` are equivalent. * The format is case insensitive. The printer will by default capitalize all designators, but the unit designators can be configured to use lowercase with [`SpanPrinter::lowercase`]. For example, `P3y1m10dT5h` instead of `P3Y1M10DT5H`. You might prefer lowercase since you may find it easier to read. However, it is an extension to ISO 8601 and isn't as broadly supported. * Hours, minutes or seconds may be fractional. And the only units that may be fractional are the lowest units. * A span like `P99999999999y` is invalid because it exceeds the allowable range of time representable by a [`Span`]. This is, roughly speaking, a subset of what [ISO 8601] specifies. It isn't strictly speaking a subset since Jiff (like Temporal) permits week units to be mixed with other units. Here are some examples: ``` use jiff::{Span, ToSpan}; let spans = [ ("P40D", 40.days()), ("P1y1d", 1.year().days(1)), ("P3dT4h59m", 3.days().hours(4).minutes(59)), ("PT2H30M", 2.hours().minutes(30)), ("P1m", 1.month()), ("P1w", 1.week()), ("P1w4d", 1.week().days(4)), ("PT1m", 1.minute()), ("PT0.0021s", 2.milliseconds().microseconds(100)), ("PT0s", 0.seconds()), ("P0d", 0.seconds()), ( "P1y1m1dT1h1m1.1s", 1.year().months(1).days(1).hours(1).minutes(1).seconds(1).milliseconds(100), ), ]; for (string, span) in spans { let parsed: Span = string.parse()?; assert_eq!( span.fieldwise(), parsed.fieldwise(), "result of parsing {string:?}", ); } # Ok::<(), Box>(()) ``` One can also parse ISO 8601 durations into a [`SignedDuration`], but units are limited to hours or smaller: ``` use jiff::SignedDuration; let durations = [ ("PT2H30M", SignedDuration::from_secs(2 * 60 * 60 + 30 * 60)), ("PT2.5h", SignedDuration::from_secs(2 * 60 * 60 + 30 * 60)), ("PT1m", SignedDuration::from_mins(1)), ("PT1.5m", SignedDuration::from_secs(90)), ("PT0.0021s", SignedDuration::new(0, 2_100_000)), ("PT0s", SignedDuration::ZERO), ("PT0.000000001s", SignedDuration::from_nanos(1)), ]; for (string, duration) in durations { let parsed: SignedDuration = string.parse()?; assert_eq!(duration, parsed, "result of parsing {string:?}"); } # Ok::<(), Box>(()) ``` The complete span format supported is described by the [Temporal ISO 8601 grammar]. # Differences with Temporal Jiff implements Temporal's grammar pretty closely, but there are a few differences at the time of writing. It is a specific goal that all differences should be rooted in what Jiff itself supports, and not in the grammar itself. * The maximum UTC offset value expressible is `25:59:59` in Jiff, where as in Temporal it's `23:59:59.999999999`. Jiff supports a slightly bigger maximum to account for all valid values of POSIX time zone strings. Jiff also lacks nanosecond precision for UTC offsets, as it's not clear how useful that is in practice. * Jiff doesn't support a datetime range as big as Temporal. For example, in Temporal, `+202024-06-14T17:30[America/New_York]` is valid. But in Jiff, since the maximum supported year is `9999`, parsing will fail. Jiff's datetime range may be expanded in the future, but it is a non-goal to match Temporal's range precisely. * Jiff doesn't support RFC 9557 calendar annotations because Jiff only supports the Gregorian calendar. There is some more [background on Temporal's format] available. [Temporal ISO 8601 grammar]: https://tc39.es/proposal-temporal/#sec-temporal-iso8601grammar [RFC 3339]: https://www.rfc-editor.org/rfc/rfc3339 [RFC 9557]: https://www.rfc-editor.org/rfc/rfc9557.html [ISO 8601]: https://www.iso.org/iso-8601-date-and-time-format.html [background on Temporal's format]: https://github.com/tc39/proposal-temporal/issues/2843