serde_datetime/chrono/
ts_microseconds_option.rs

1use core::fmt;
2
3use chrono::{DateTime, Utc};
4use serde::{de, ser};
5
6pub(super) struct OptionMicroSecondsTimestampVisitor;
7use super::ts_microseconds::MicroSecondsTimestampVisitor;
8
9pub fn serialize<S>(opt: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error>
10where
11    S: ser::Serializer,
12{
13    match *opt {
14        Some(ref dt) => serializer.serialize_some(&dt.timestamp_micros()),
15        None => serializer.serialize_none(),
16    }
17}
18
19pub fn deserialize<'de, D>(d: D) -> Result<Option<DateTime<Utc>>, D::Error>
20where
21    D: de::Deserializer<'de>,
22{
23    d.deserialize_option(OptionMicroSecondsTimestampVisitor)
24        .map(|opt| opt.map(|dt| dt.with_timezone(&Utc)))
25}
26
27impl<'de> de::Visitor<'de> for OptionMicroSecondsTimestampVisitor {
28    type Value = Option<DateTime<Utc>>;
29
30    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
31        formatter.write_str("a unix timestamp in microseconds or none")
32    }
33
34    /// Deserialize a timestamp in microseconds since the epoch
35    fn visit_some<D>(self, d: D) -> Result<Option<DateTime<Utc>>, D::Error>
36    where
37        D: de::Deserializer<'de>,
38    {
39        d.deserialize_i64(MicroSecondsTimestampVisitor).map(Some)
40    }
41
42    /// Deserialize a timestamp in microseconds since the epoch
43    fn visit_none<E>(self) -> Result<Option<DateTime<Utc>>, E>
44    where
45        E: de::Error,
46    {
47        Ok(None)
48    }
49
50    /// Deserialize a timestamp in microseconds since the epoch
51    fn visit_unit<E>(self) -> Result<Option<DateTime<Utc>>, E>
52    where
53        E: de::Error,
54    {
55        Ok(None)
56    }
57}
58
59#[cfg(test)]
60mod tests {
61    use std::error::Error;
62
63    use chrono::{DateTime, NaiveDate, Utc};
64    use serde::{Deserialize, Serialize};
65    use serde_json::json;
66
67    use crate::chrono::ts_microseconds_option;
68
69    #[test]
70    fn test_ts_microseconds_option() -> Result<(), Box<dyn Error>> {
71        #[derive(Deserialize, Serialize, Debug)]
72        struct S {
73            #[serde(default, with = "ts_microseconds_option")]
74            time: Option<DateTime<Utc>>,
75        }
76
77        //
78        let s: S = serde_json::from_str(r#"{ "time": null }"#)?;
79        assert_eq!(s.time, None);
80
81        let s: S = serde_json::from_str(r#"{ "time": 1609459200999999 }"#)?;
82        assert_eq!(
83            s.time,
84            Some(DateTime::from_utc(
85                NaiveDate::from_ymd_opt(2021, 1, 1)
86                    .expect("")
87                    .and_hms_micro_opt(0, 0, 0, 999999)
88                    .expect(""),
89                Utc
90            ))
91        );
92
93        //
94        let s = S { time: None };
95        assert_eq!(serde_json::to_value(&s)?, json!({ "time": null }));
96
97        let s = S {
98            time: Some(DateTime::from_utc(
99                NaiveDate::from_ymd_opt(2021, 1, 1)
100                    .expect("")
101                    .and_hms_micro_opt(0, 0, 0, 999999)
102                    .expect(""),
103                Utc,
104            )),
105        };
106        assert_eq!(
107            serde_json::to_value(&s)?,
108            json!({ "time": 1609459200999999_u64 })
109        );
110
111        Ok(())
112    }
113}