1use std::time::Duration;
5use std::time::SystemTime;
6use std::time::UNIX_EPOCH;
7
8#[cfg(feature = "chrono-tz")]
9use chrono::{
10 offset::TimeZone as _,
11 DateTime,
12 Utc,
13};
14#[cfg(feature = "chrono-tz")]
15use chrono_tz::America::New_York;
16
17use serde::de::Deserializer;
18use serde::de::Error;
19use serde::de::Unexpected;
20use serde::ser::Serializer;
21use serde::Deserialize;
22
23use crate::parse::parse_system_time_from_str_impl;
24use crate::parse::DATE_PARSE_FNS;
25use crate::parse::TIME_PARSE_FNS;
26use crate::print::print_system_time_to_rfc3339;
27use crate::print::print_system_time_to_rfc3339_with_nanos;
28
29
30pub fn system_time_from_str<'de, D>(deserializer: D) -> Result<SystemTime, D::Error>
32where
33 D: Deserializer<'de>,
34{
35 let time = String::deserialize(deserializer)?;
36 parse_system_time_from_str_impl(&time, &TIME_PARSE_FNS)
37 .ok_or_else(|| Error::invalid_value(Unexpected::Str(&time), &"a time stamp string"))
38}
39
40
41pub fn optional_system_time_from_str<'de, D>(
43 deserializer: D,
44) -> Result<Option<SystemTime>, D::Error>
45where
46 D: Deserializer<'de>,
47{
48 match Option::<String>::deserialize(deserializer)? {
49 Some(time) => parse_system_time_from_str_impl(&time, &TIME_PARSE_FNS)
50 .ok_or_else(|| Error::invalid_value(Unexpected::Str(&time), &"an optional time stamp string"))
51 .map(Option::Some),
52 None => Ok(None),
53 }
54}
55
56
57pub fn system_time_from_date_str<'de, D>(deserializer: D) -> Result<SystemTime, D::Error>
59where
60 D: Deserializer<'de>,
61{
62 let date = String::deserialize(deserializer)?;
63 parse_system_time_from_str_impl(&date, &DATE_PARSE_FNS)
64 .ok_or_else(|| Error::invalid_value(Unexpected::Str(&date), &"a date string"))
65}
66
67
68pub fn system_time_from_secs<'de, D>(deserializer: D) -> Result<SystemTime, D::Error>
70where
71 D: Deserializer<'de>,
72{
73 let seconds = u64::deserialize(deserializer)?;
74 let time = UNIX_EPOCH + Duration::new(seconds, 0);
75 Ok(time)
76}
77
78
79pub fn system_time_from_millis<'de, D>(deserializer: D) -> Result<SystemTime, D::Error>
82where
83 D: Deserializer<'de>,
84{
85 let ms = u64::deserialize(deserializer)?;
86 let time = UNIX_EPOCH + Duration::from_millis(ms);
87 Ok(time)
88}
89
90
91#[cfg(feature = "chrono-tz")]
94pub fn system_time_from_millis_in_new_york<'de, D>(deserializer: D) -> Result<SystemTime, D::Error>
95where
96 D: Deserializer<'de>,
97{
98 let time = system_time_from_millis(deserializer)?;
99 let naive_time = DateTime::<Utc>::from(time).naive_local();
100 let ny_time = New_York.from_utc_datetime(&naive_time);
101 let utc_time = Utc.from_local_datetime(&ny_time.naive_local()).unwrap();
102
103 Ok(SystemTime::from(utc_time))
104}
105
106
107pub fn system_time_to_rfc3339<S>(time: &SystemTime, serializer: S) -> Result<S::Ok, S::Error>
109where
110 S: Serializer,
111{
112 let string = print_system_time_to_rfc3339(time);
113 serializer.serialize_str(&string)
114}
115
116
117pub fn system_time_to_rfc3339_with_nanos<S>(
119 time: &SystemTime,
120 serializer: S,
121) -> Result<S::Ok, S::Error>
122where
123 S: Serializer,
124{
125 let string = print_system_time_to_rfc3339_with_nanos(time);
126 serializer.serialize_str(&string)
127}
128
129
130pub fn optional_system_time_to_rfc3339<S>(
132 time: &Option<SystemTime>,
133 serializer: S,
134) -> Result<S::Ok, S::Error>
135where
136 S: Serializer,
137{
138 match time {
139 Some(time) => system_time_to_rfc3339(time, serializer),
140 None => serializer.serialize_none(),
141 }
142}
143
144
145pub fn optional_system_time_to_rfc3339_with_nanos<S>(
147 time: &Option<SystemTime>,
148 serializer: S,
149) -> Result<S::Ok, S::Error>
150where
151 S: Serializer,
152{
153 match time {
154 Some(time) => system_time_to_rfc3339_with_nanos(time, serializer),
155 None => serializer.serialize_none(),
156 }
157}
158
159
160pub fn system_time_to_millis<S>(time: &SystemTime, serializer: S) -> Result<S::Ok, S::Error>
163where
164 S: Serializer,
165{
166 let millis = time.duration_since(UNIX_EPOCH).unwrap().as_millis();
170 serializer.serialize_u128(millis)
171}
172
173
174#[cfg(feature = "chrono-tz")]
177pub fn system_time_to_millis_in_new_york<S>(
178 time: &SystemTime,
179 serializer: S,
180) -> Result<S::Ok, S::Error>
181where
182 S: Serializer,
183{
184 let utc_time = DateTime::<Utc>::from(*time);
185 let ny_time = New_York.from_local_datetime(&utc_time.naive_utc()).unwrap();
186 system_time_to_millis(&SystemTime::from(ny_time), serializer)
187}
188
189
190#[cfg(test)]
191mod tests {
192 use super::*;
193
194 use std::time::SystemTime;
195
196 use serde::Deserialize;
197 use serde::Serialize;
198 use serde_json::from_str as from_json;
199 use serde_json::to_string as to_json;
200
201 #[cfg(feature = "chrono-tz")]
202 use crate::parse::parse_system_time_from_str;
203
204
205 #[derive(Debug, Deserialize)]
206 struct Time {
207 #[serde(deserialize_with = "system_time_from_str")]
208 time: SystemTime,
209 }
210
211 #[test]
212 fn deserialize_system_time_from_str() {
213 let times = [
214 r#"{"time": "2018-04-01T12:00:00Z"}"#,
215 r#"{"time": "2018-04-01T12:00:00.000Z"}"#,
216 r#"{"time": "2018-04-01T08:00:00.000-04:00"}"#,
217 ];
218
219 for json in × {
220 let time = from_json::<Time>(json).unwrap();
221 assert_eq!(time.time, UNIX_EPOCH + Duration::from_secs(1_522_584_000));
222 }
223 }
224
225 #[derive(Debug, Deserialize)]
226 struct Date {
227 #[serde(deserialize_with = "system_time_from_date_str")]
228 date: SystemTime,
229 }
230
231 #[test]
232 fn deserialize_system_time_from_date_str() {
233 let dates = [r#"{"date": "2019-08-01"}"#];
234
235 for json in &dates {
236 let date = from_json::<Date>(json).unwrap();
237 assert_eq!(date.date, UNIX_EPOCH + Duration::from_secs(1_564_617_600));
238 }
239 }
240
241
242 #[derive(Debug, Deserialize, Serialize)]
243 struct OtherTime {
244 #[serde(
245 deserialize_with = "system_time_from_secs",
246 serialize_with = "system_time_to_rfc3339",
247 )]
248 time: SystemTime,
249 }
250
251 #[test]
252 fn deserialize_system_time_from_secs() {
253 let time = from_json::<OtherTime>(r#"{"time": 1544129220}"#).unwrap();
254 assert_eq!(time.time, UNIX_EPOCH + Duration::from_secs(1_544_129_220));
255 }
256
257 #[test]
258 fn serialize_system_time_to_rfc3339() {
259 let time = OtherTime {
260 time: UNIX_EPOCH + Duration::from_secs(1_544_129_220),
261 };
262 let json = to_json(&time).unwrap();
263 assert_eq!(json, r#"{"time":"2018-12-06T20:47:00.000Z"}"#);
264 }
265
266 #[derive(Debug, Deserialize, Serialize)]
267 struct MsTime {
268 #[serde(
269 deserialize_with = "system_time_from_millis",
270 serialize_with = "system_time_to_rfc3339",
271 )]
272 time: SystemTime,
273 }
274
275 #[test]
276 fn deserialize_system_time_from_millis() {
277 let time = from_json::<MsTime>(r#"{"time": 1517461200000}"#).unwrap();
278 assert_eq!(time.time, UNIX_EPOCH + Duration::from_secs(1_517_461_200));
279 }
280
281
282 #[derive(Debug, Deserialize, Serialize)]
283 #[cfg(feature = "chrono-tz")]
284 struct MsTimeNY {
285 #[serde(
286 deserialize_with = "system_time_from_millis_in_new_york",
287 serialize_with = "system_time_to_millis_in_new_york",
288 )]
289 time: SystemTime,
290 }
291
292 #[test]
293 #[cfg(feature = "chrono-tz")]
294 fn deserialize_serialize_system_time_millis_in_new_york() {
295 let time = from_json::<MsTimeNY>(r#"{"time": 1517461200000}"#).unwrap();
298 let expected = parse_system_time_from_str("2018-02-01T00:00:00.000Z").unwrap();
299 assert_eq!(time.time, expected);
300
301 let json = to_json::<MsTimeNY>(&time).unwrap();
302 let time = from_json::<MsTimeNY>(&json).unwrap();
303 assert_eq!(time.time, expected);
304 }
305
306 #[test]
307 #[cfg(feature = "chrono-tz")]
308 fn deserialize_serialize_system_time_millis_in_new_york_daylight_savings() {
309 let time = from_json::<MsTimeNY>(r#"{"time": 1599537600000}"#).unwrap();
310 let expected = parse_system_time_from_str("2020-09-08T00:00:00.000Z").unwrap();
311 assert_eq!(time.time, expected);
312
313 let json = to_json::<MsTimeNY>(&time).unwrap();
314 let time = from_json::<MsTimeNY>(&json).unwrap();
315 assert_eq!(time.time, expected);
316 }
317}