Skip to main content

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
67    use chrono::{DateTime, NaiveDate, Utc};
68    use serde::{Deserialize, Serialize};
69    use serde_json::json;
70
71    use crate::chrono::ts_float_microseconds_option;
72
73    #[test]
74    fn test_ts_float_microseconds_option() -> Result<(), serde_json::Error> {
75        #[derive(Deserialize, Serialize, Debug)]
76        struct S {
77            #[serde(default, with = "ts_float_microseconds_option")]
78            time: Option<DateTime<Utc>>,
79        }
80
81        //
82        let s: S = serde_json::from_str(r#"{ "time": null }"#)?;
83        assert_eq!(s.time, None);
84
85        let s: S = serde_json::from_str(r#"{ "time": 1609459200.999999 }"#)?;
86        assert_eq!(
87            s.time,
88            Some(DateTime::from_naive_utc_and_offset(
89                NaiveDate::from_ymd_opt(2021, 1, 1)
90                    .expect("")
91                    .and_hms_micro_opt(0, 0, 0, 999999)
92                    .expect(""),
93                Utc
94            ))
95        );
96
97        let s: S = serde_json::from_str(r#"{ "time": 1609459200 }"#)?;
98        assert_eq!(
99            s.time,
100            Some(DateTime::from_naive_utc_and_offset(
101                NaiveDate::from_ymd_opt(2021, 1, 1)
102                    .expect("")
103                    .and_hms_micro_opt(0, 0, 0, 0)
104                    .expect(""),
105                Utc
106            ))
107        );
108
109        let s: S = serde_json::from_str(r#"{ "time": 1609459200.000001 }"#)?;
110        assert_eq!(
111            s.time,
112            Some(DateTime::from_naive_utc_and_offset(
113                NaiveDate::from_ymd_opt(2021, 1, 1)
114                    .expect("")
115                    .and_hms_micro_opt(0, 0, 0, 1)
116                    .expect(""),
117                Utc
118            ))
119        );
120
121        //
122        let s = S { time: None };
123        assert_eq!(serde_json::to_value(s)?, json!({ "time": null }));
124
125        let s = S {
126            time: Some(DateTime::from_naive_utc_and_offset(
127                NaiveDate::from_ymd_opt(2021, 1, 1)
128                    .expect("")
129                    .and_hms_micro_opt(0, 0, 0, 999999)
130                    .expect(""),
131                Utc,
132            )),
133        };
134        assert_eq!(
135            serde_json::to_value(s)?,
136            json!({ "time": 1609459200.999999 })
137        );
138
139        let s = S {
140            time: Some(DateTime::from_naive_utc_and_offset(
141                NaiveDate::from_ymd_opt(2021, 1, 1)
142                    .expect("")
143                    .and_hms_micro_opt(0, 0, 0, 0)
144                    .expect(""),
145                Utc,
146            )),
147        };
148        assert_eq!(
149            serde_json::to_value(s)?,
150            json!({ "time": 1609459200.000000 })
151        );
152
153        let s = S {
154            time: Some(DateTime::from_naive_utc_and_offset(
155                NaiveDate::from_ymd_opt(2021, 1, 1)
156                    .expect("")
157                    .and_hms_micro_opt(0, 0, 0, 1)
158                    .expect(""),
159                Utc,
160            )),
161        };
162        assert_eq!(
163            serde_json::to_value(s)?,
164            json!({ "time": 1609459200.000001 })
165        );
166
167        Ok(())
168    }
169}