serde_datetime/chrono/
ts_float_microseconds_option.rs

1use core::fmt;
2
3use chrono::{DateTime, Utc};
4use serde::{de, ser};
5
6pub(super) struct OptionFloatMicroSecondsTimestampVisitor;
7use super::ts_float_microseconds::FloatMicroSecondsTimestampVisitor;
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) => {
15            let f64 =
16                dt.timestamp() as f64 + f64::from(dt.timestamp_subsec_micros()) / 1_000_000_f64;
17            serializer.serialize_some(&f64)
18        }
19        None => serializer.serialize_none(),
20    }
21}
22
23pub fn deserialize<'de, D>(d: D) -> Result<Option<DateTime<Utc>>, D::Error>
24where
25    D: de::Deserializer<'de>,
26{
27    d.deserialize_option(OptionFloatMicroSecondsTimestampVisitor)
28        .map(|opt| opt.map(|dt| dt.with_timezone(&Utc)))
29}
30
31impl<'de> de::Visitor<'de> for OptionFloatMicroSecondsTimestampVisitor {
32    type Value = Option<DateTime<Utc>>;
33
34    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
35        formatter.write_str("a unix timestamp in float microseconds or none")
36    }
37
38    /// Deserialize a timestamp in float microseconds since the epoch
39    fn visit_some<D>(self, d: D) -> Result<Option<DateTime<Utc>>, D::Error>
40    where
41        D: de::Deserializer<'de>,
42    {
43        d.deserialize_i64(FloatMicroSecondsTimestampVisitor)
44            .map(Some)
45    }
46
47    /// Deserialize a timestamp in float microseconds since the epoch
48    fn visit_none<E>(self) -> Result<Option<DateTime<Utc>>, E>
49    where
50        E: de::Error,
51    {
52        Ok(None)
53    }
54
55    /// Deserialize a timestamp in float microseconds since the epoch
56    fn visit_unit<E>(self) -> Result<Option<DateTime<Utc>>, E>
57    where
58        E: de::Error,
59    {
60        Ok(None)
61    }
62}
63
64#[cfg(test)]
65mod tests {
66    use std::error::Error;
67
68    use chrono::{DateTime, NaiveDate, Utc};
69    use serde::{Deserialize, Serialize};
70    use serde_json::json;
71
72    use crate::chrono::ts_float_microseconds_option;
73
74    #[test]
75    fn test_ts_float_microseconds_option() -> Result<(), Box<dyn Error>> {
76        #[derive(Deserialize, Serialize, Debug)]
77        struct S {
78            #[serde(default, with = "ts_float_microseconds_option")]
79            time: Option<DateTime<Utc>>,
80        }
81
82        //
83        let s: S = serde_json::from_str(r#"{ "time": null }"#)?;
84        assert_eq!(s.time, None);
85
86        let s: S = serde_json::from_str(r#"{ "time": 1609459200.999999 }"#)?;
87        assert_eq!(
88            s.time,
89            Some(DateTime::from_utc(
90                NaiveDate::from_ymd_opt(2021, 1, 1)
91                    .expect("")
92                    .and_hms_micro_opt(0, 0, 0, 999999)
93                    .expect(""),
94                Utc
95            ))
96        );
97
98        let s: S = serde_json::from_str(r#"{ "time": 1609459200 }"#)?;
99        assert_eq!(
100            s.time,
101            Some(DateTime::from_utc(
102                NaiveDate::from_ymd_opt(2021, 1, 1)
103                    .expect("")
104                    .and_hms_micro_opt(0, 0, 0, 0)
105                    .expect(""),
106                Utc
107            ))
108        );
109
110        let s: S = serde_json::from_str(r#"{ "time": 1609459200.000001 }"#)?;
111        assert_eq!(
112            s.time,
113            Some(DateTime::from_utc(
114                NaiveDate::from_ymd_opt(2021, 1, 1)
115                    .expect("")
116                    .and_hms_micro_opt(0, 0, 0, 1)
117                    .expect(""),
118                Utc
119            ))
120        );
121
122        //
123        let s = S { time: None };
124        assert_eq!(serde_json::to_value(&s)?, json!({ "time": null }));
125
126        let s = S {
127            time: Some(DateTime::from_utc(
128                NaiveDate::from_ymd_opt(2021, 1, 1)
129                    .expect("")
130                    .and_hms_micro_opt(0, 0, 0, 999999)
131                    .expect(""),
132                Utc,
133            )),
134        };
135        assert_eq!(
136            serde_json::to_value(&s)?,
137            json!({ "time": 1609459200.999999 })
138        );
139
140        let s = S {
141            time: Some(DateTime::from_utc(
142                NaiveDate::from_ymd_opt(2021, 1, 1)
143                    .expect("")
144                    .and_hms_micro_opt(0, 0, 0, 0)
145                    .expect(""),
146                Utc,
147            )),
148        };
149        assert_eq!(
150            serde_json::to_value(&s)?,
151            json!({ "time": 1609459200.000000 })
152        );
153
154        let s = S {
155            time: Some(DateTime::from_utc(
156                NaiveDate::from_ymd_opt(2021, 1, 1)
157                    .expect("")
158                    .and_hms_micro_opt(0, 0, 0, 1)
159                    .expect(""),
160                Utc,
161            )),
162        };
163        assert_eq!(
164            serde_json::to_value(&s)?,
165            json!({ "time": 1609459200.000001 })
166        );
167
168        Ok(())
169    }
170}