serde_datetime/chrono/
ts_float_microseconds_option.rs1use 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 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 fn visit_none<E>(self) -> Result<Option<DateTime<Utc>>, E>
49 where
50 E: de::Error,
51 {
52 Ok(None)
53 }
54
55 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 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 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}