Line data Source code
1 : //! A `serde::{Deserialize,Serialize}` type for SystemTime with RFC3339 format and millisecond precision.
2 :
3 6 : #[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 12 : fn ser_rfc3339_millis<S: serde::ser::Serializer>(
14 12 : ts: &std::time::SystemTime,
15 12 : serializer: S,
16 12 : ) -> Result<S::Ok, S::Error> {
17 12 : serializer.collect_str(&humantime::format_rfc3339_millis(*ts))
18 12 : }
19 :
20 6 : fn deser_rfc3339_millis<'de, D>(deserializer: D) -> Result<std::time::SystemTime, D::Error>
21 6 : where
22 6 : D: serde::de::Deserializer<'de>,
23 6 : {
24 6 : let s: String = serde::de::Deserialize::deserialize(deserializer)?;
25 6 : humantime::parse_rfc3339(&s).map_err(serde::de::Error::custom)
26 6 : }
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 6 : fn to_millisecond_precision(time: SystemTime) -> SystemTime {
34 6 : match time.0.duration_since(std::time::SystemTime::UNIX_EPOCH) {
35 6 : Ok(duration) => {
36 6 : let total_millis = duration.as_secs() * 1_000 + u64::from(duration.subsec_millis());
37 6 : SystemTime(
38 6 : std::time::SystemTime::UNIX_EPOCH
39 6 : + std::time::Duration::from_millis(total_millis),
40 6 : )
41 : }
42 0 : Err(_) => time,
43 : }
44 6 : }
45 :
46 : #[test]
47 6 : fn test_serialize_deserialize() {
48 6 : let input = SystemTime(std::time::SystemTime::now());
49 6 : let expected_serialized = format!("\"{}\"", humantime::format_rfc3339_millis(input.0));
50 6 : let serialized = serde_json::to_string(&input).unwrap();
51 6 : assert_eq!(expected_serialized, serialized);
52 6 : let deserialized: SystemTime = serde_json::from_str(&expected_serialized).unwrap();
53 6 : assert_eq!(to_millisecond_precision(input), deserialized);
54 6 : }
55 : }
|