Line data Source code
1 : //! A `serde::{Deserialize,Serialize}` type for SystemTime with RFC3339 format and millisecond precision.
2 :
3 1 : #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)]
4 : #[serde(transparent)]
5 : pub struct SystemTime(
6 : #[serde(
7 : deserialize_with = "deser_rfc3339_millis",
8 : serialize_with = "ser_rfc3339_millis"
9 : )]
10 : pub std::time::SystemTime,
11 : );
12 :
13 2 : fn ser_rfc3339_millis<S: serde::ser::Serializer>(
14 2 : ts: &std::time::SystemTime,
15 2 : serializer: S,
16 2 : ) -> Result<S::Ok, S::Error> {
17 2 : serializer.collect_str(&humantime::format_rfc3339_millis(*ts))
18 2 : }
19 :
20 1 : fn deser_rfc3339_millis<'de, D>(deserializer: D) -> Result<std::time::SystemTime, D::Error>
21 1 : where
22 1 : D: serde::de::Deserializer<'de>,
23 1 : {
24 1 : let s: String = serde::de::Deserialize::deserialize(deserializer)?;
25 1 : humantime::parse_rfc3339(&s).map_err(serde::de::Error::custom)
26 1 : }
27 :
28 : #[cfg(test)]
29 : mod tests {
30 : use super::*;
31 :
32 : /// Helper function to make a SystemTime have millisecond precision by truncating additional nanoseconds.
33 1 : fn to_millisecond_precision(time: SystemTime) -> SystemTime {
34 1 : match time.0.duration_since(std::time::SystemTime::UNIX_EPOCH) {
35 1 : Ok(duration) => {
36 1 : let total_millis = duration.as_secs() * 1_000 + u64::from(duration.subsec_millis());
37 1 : SystemTime(
38 1 : std::time::SystemTime::UNIX_EPOCH
39 1 : + std::time::Duration::from_millis(total_millis),
40 1 : )
41 : }
42 0 : Err(_) => time,
43 : }
44 1 : }
45 :
46 : #[test]
47 1 : fn test_serialize_deserialize() {
48 1 : let input = SystemTime(std::time::SystemTime::now());
49 1 : let expected_serialized = format!("\"{}\"", humantime::format_rfc3339_millis(input.0));
50 1 : let serialized = serde_json::to_string(&input).unwrap();
51 1 : assert_eq!(expected_serialized, serialized);
52 1 : let deserialized: SystemTime = serde_json::from_str(&expected_serialized).unwrap();
53 1 : assert_eq!(to_millisecond_precision(input), deserialized);
54 1 : }
55 : }
|