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