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 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 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 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}