Module temporal
dep_jiff
and alloc
only.Expand description
A hybrid format derived from RFC 3339, RFC 9557 and ISO 8601.
This module provides an implementation of the Temporal ISO 8601 grammar. The API is spread out over parsers and printers for datetimes and spans.
Note that for most use cases, you should be using the corresponding
Display
or 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 acivil::Time
.2020-08-21
parses into acivil::Date
.2020-08-21T02:21:58
and2020-08-21 02:21:58
both parse into acivil::DateTime
.2020-08-21T02:21:58-04
parses into anTimestamp
.2020-08-21T02:21:58-04[America/New_York]
parses into aZoned
.
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 anTimestamp
. From there, it can be converted to aZoned
viaTimestamp::to_zoned
. - When parsing
Zoned
values, ambiguous datetimes are handled via theDateTimeParser::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 theDateTimeParser::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 aZ
(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:
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
andPT0s
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 ofP3Y1M10DT5H
. 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 aSpan
.
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, parsed, "result of parsing {string:?}");
}
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:?}");
}
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’s23: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 is9999
, 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.
Structs§
- A parser for Temporal datetimes.
- A printer for Temporal datetimes.
- A low level representation of a parsed Temporal ISO 8601 datetime string.
- A specific numeric offset, including the sign of the offset, for use with
Pieces
. - A parser for Temporal durations.
- A printer for Temporal durations.
- A time zone annotation parsed from a datetime string.
Enums§
- An offset parsed from a Temporal ISO 8601 datetime string, for use with
Pieces
.