typeshare/
json_date.rs

1use chrono::{DateTime, SecondsFormat, Utc};
2use serde::de::{Error, Unexpected, Visitor};
3use serde::{Deserializer, Serializer};
4use std::fmt;
5
6struct DateTimeVisitor;
7
8pub fn serialize<S>(dt: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error>
9where
10    S: Serializer,
11{
12    serializer.serialize_str(dt.to_rfc3339_opts(SecondsFormat::Millis, true).as_str())
13}
14
15pub fn deserialize<'de, D>(d: D) -> Result<DateTime<Utc>, D::Error>
16where
17    D: Deserializer<'de>,
18{
19    d.deserialize_str(DateTimeVisitor)
20}
21
22impl<'de> Visitor<'de> for DateTimeVisitor {
23    type Value = DateTime<Utc>;
24
25    fn expecting(&self, w: &mut fmt::Formatter) -> fmt::Result {
26        write!(w, "date and time in ISO 8601")
27    }
28
29    /// Deserialize a ISO 8601 formatted time
30    fn visit_borrowed_str<E>(self, value: &'de str) -> Result<DateTime<Utc>, E>
31    where
32        E: Error,
33    {
34        Ok(DateTime::parse_from_rfc3339(value)
35            .map_err(|_| Error::invalid_value(Unexpected::Str(value), &self))?
36            .with_timezone(&Utc))
37    }
38}
39
40#[cfg(test)]
41mod tests {
42    use super::*;
43    use chrono::Utc;
44    use serde::{Deserialize, Serialize};
45
46    #[derive(Debug, Serialize, Deserialize, PartialEq)]
47    struct Test {
48        #[serde(with = "super")]
49        time: DateTime<Utc>,
50    }
51
52    #[test]
53    fn test_deserialize() {
54        let data = r#"{"time":"2020-02-01T03:16:46.229Z"}"#;
55        let expect = Test {
56            time: DateTime::from_timestamp(1_580_527_006, 229_000_000).unwrap(),
57        };
58
59        assert_eq!(serde_json::from_str::<Test>(data).unwrap(), expect);
60    }
61
62    #[test]
63    fn test_serialize() {
64        let data = Test {
65            time: DateTime::from_timestamp(1_580_527_006, 229_000_000).unwrap(),
66        };
67        let expect = r#"{"time":"2020-02-01T03:16:46.229Z"}"#;
68
69        assert_eq!(serde_json::to_string(&data).unwrap(), expect);
70    }
71}