Expand description
Convenience routines for serializing std::time::Duration values.
The principal helpers in this module are the
required
and
optional sub-modules.
Either may be used with Serde’s with attribute. Each sub-module
provides both a serialization and a deserialization routine for
std::time::Duration. Deserialization supports either ISO 8601 or the
“friendly” format. Serialization always uses ISO
8601 for reasons of increased interoperability. These helpers are meant to
approximate the Deserialize and Serialize trait implementations for
Jiff’s own SignedDuration.
If you want to serialize a std::time::Duration using the
friendly, then you can make use of the
helpers in
friendly::compact,
also via Serde’s with attribute. These helpers change their serialization
to the “friendly” format using compact unit designators. Their deserialization
remains the same as the top-level helpers (that is, both ISO 8601 and
friendly formatted duration strings are parsed).
Unlike Jiff’s own SignedDuration, deserializing
a std::time::Duration does not support negative durations. If a negative
duration is found, then deserialization will fail. Moreover, as an unsigned
type, a std::time::Duration can represent larger durations than a
SignedDuration. This means that a SignedDuration cannot deserialize
all valid values of a std::time::Duration. In other words, be careful not
to mix them.
§Example: maximally interoperable serialization
This example shows how to achieve Serde integration for std::time::Duration
in a way that mirrors SignedDuration. In
particular, this supports deserializing ISO 8601 or “friendly” format
duration strings. In order to be maximally interoperable, this serializes
only in the ISO 8601 format.
use std::time::Duration;
use serde::{Deserialize, Serialize};
#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct Task {
name: String,
#[serde(with = "jiff::fmt::serde::unsigned_duration::required")]
timeout: Duration,
#[serde(with = "jiff::fmt::serde::unsigned_duration::optional")]
retry_delay: Option<Duration>,
}
let task = Task {
name: "Task 1".to_string(),
// 1 hour 30 minutes
timeout: Duration::from_secs(60 * 60 + 30 * 60),
// 2 seconds 500 milliseconds
retry_delay: Some(Duration::from_millis(2500)),
};
let expected_json = r#"{"name":"Task 1","timeout":"PT1H30M","retry_delay":"PT2.5S"}"#;
let actual_json = serde_json::to_string(&task)?;
assert_eq!(actual_json, expected_json);
let deserialized_task: Task = serde_json::from_str(&actual_json)?;
assert_eq!(deserialized_task, task);
// Example with None for optional field
let task_no_retry = Task {
name: "Task 2".to_string(),
timeout: Duration::from_secs(5),
retry_delay: None,
};
let expected_json_no_retry = r#"{"name":"Task 2","timeout":"PT5S","retry_delay":null}"#;
let actual_json_no_retry = serde_json::to_string(&task_no_retry)?;
assert_eq!(actual_json_no_retry, expected_json_no_retry);
let deserialized_task_no_retry: Task = serde_json::from_str(&actual_json_no_retry)?;
assert_eq!(deserialized_task_no_retry, task_no_retry);
§Example: Round-tripping std::time::Duration
This example demonstrates how to serialize and deserialize a
std::time::Duration field using the helpers from this module. In
particular, this serializes durations in the more human readable
“friendly” format, but can still deserialize ISO 8601 duration strings.
use std::time::Duration;
use serde::{Deserialize, Serialize};
#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct Task {
name: String,
#[serde(with = "jiff::fmt::serde::unsigned_duration::friendly::compact::required")]
timeout: Duration,
#[serde(with = "jiff::fmt::serde::unsigned_duration::friendly::compact::optional")]
retry_delay: Option<Duration>,
}
let task = Task {
name: "Task 1".to_string(),
// 1 hour 30 minutes
timeout: Duration::from_secs(60 * 60 + 30 * 60),
// 2 seconds 500 milliseconds
retry_delay: Some(Duration::from_millis(2500)),
};
let expected_json = r#"{"name":"Task 1","timeout":"1h 30m","retry_delay":"2s 500ms"}"#;
let actual_json = serde_json::to_string(&task)?;
assert_eq!(actual_json, expected_json);
let deserialized_task: Task = serde_json::from_str(&actual_json)?;
assert_eq!(deserialized_task, task);
// Example with None for optional field
let task_no_retry = Task {
name: "Task 2".to_string(),
timeout: Duration::from_secs(5),
retry_delay: None,
};
let expected_json_no_retry = r#"{"name":"Task 2","timeout":"5s","retry_delay":null}"#;
let actual_json_no_retry = serde_json::to_string(&task_no_retry)?;
assert_eq!(actual_json_no_retry, expected_json_no_retry);
let deserialized_task_no_retry: Task = serde_json::from_str(&actual_json_no_retry)?;
assert_eq!(deserialized_task_no_retry, task_no_retry);
§Example: custom “friendly” format options
When using
friendly::compact,
the serialization implementation uses a fixed friendly format
configuration. To use your own configuration, you’ll need to write your own
serialization function:
use std::time::Duration;
#[derive(Debug, serde::Deserialize, serde::Serialize)]
struct Data {
#[serde(serialize_with = "custom_friendly")]
// We can reuse an existing deserialization helper so that you
// don't have to write your own.
#[serde(deserialize_with = "jiff::fmt::serde::unsigned_duration::required::deserialize")]
duration: Duration,
}
let json = r#"{"duration": "36 hours 1100ms"}"#;
let got: Data = serde_json::from_str(&json).unwrap();
assert_eq!(got.duration, Duration::new(36 * 60 * 60 + 1, 100_000_000));
let expected = r#"{"duration":"36:00:01.100"}"#;
assert_eq!(serde_json::to_string(&got).unwrap(), expected);
fn custom_friendly<S: serde::Serializer>(
duration: &Duration,
se: S,
) -> Result<S::Ok, S::Error> {
struct Custom<'a>(&'a Duration);
impl<'a> std::fmt::Display for Custom<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
use jiff::fmt::{friendly::SpanPrinter, StdFmtWrite};
static PRINTER: SpanPrinter = SpanPrinter::new()
.hours_minutes_seconds(true)
.precision(Some(3));
PRINTER
.print_unsigned_duration(self.0, StdFmtWrite(f))
.map_err(|_| core::fmt::Error)
}
}
se.collect_str(&Custom(duration))
}Modules§
- friendly
- (De)serialize a
std::time::Durationin thefriendlyduration format. - optional
- (De)serialize an optional ISO 8601 or friendly duration from a
std::time::Duration. - required
- (De)serialize a required ISO 8601 or friendly duration from a
std::time::Duration.