1 | use core::fmt; |
2 | use serde::{de, ser}; |
3 | |
4 | use super::DateTime; |
5 | use crate::format::{write_rfc3339, SecondsFormat}; |
6 | #[cfg (feature = "clock" )] |
7 | use crate::offset::Local; |
8 | use crate::offset::{FixedOffset, Offset, TimeZone, Utc}; |
9 | |
10 | #[doc (hidden)] |
11 | #[derive (Debug)] |
12 | pub struct SecondsTimestampVisitor; |
13 | |
14 | #[doc (hidden)] |
15 | #[derive (Debug)] |
16 | pub struct NanoSecondsTimestampVisitor; |
17 | |
18 | #[doc (hidden)] |
19 | #[derive (Debug)] |
20 | pub struct MicroSecondsTimestampVisitor; |
21 | |
22 | #[doc (hidden)] |
23 | #[derive (Debug)] |
24 | pub struct MilliSecondsTimestampVisitor; |
25 | |
26 | /// Serialize to an RFC 3339 formatted string |
27 | /// |
28 | /// As an extension to RFC 3339 this can serialize `DateTime`s outside the range of 0-9999 years |
29 | /// using an ISO 8601 syntax (which prepends an `-` or `+`). |
30 | /// |
31 | /// See [the `serde` module](crate::serde) for alternate serializations. |
32 | impl<Tz: TimeZone> ser::Serialize for DateTime<Tz> { |
33 | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> |
34 | where |
35 | S: ser::Serializer, |
36 | { |
37 | struct FormatIso8601<'a, Tz: TimeZone> { |
38 | inner: &'a DateTime<Tz>, |
39 | } |
40 | |
41 | impl<Tz: TimeZone> fmt::Display for FormatIso8601<'_, Tz> { |
42 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
43 | let naive: NaiveDateTime = self.inner.naive_local(); |
44 | let offset: FixedOffset = self.inner.offset.fix(); |
45 | write_rfc3339(w:f, dt:naive, off:offset, secform:SecondsFormat::AutoSi, use_z:true) |
46 | } |
47 | } |
48 | |
49 | serializer.collect_str(&FormatIso8601 { inner: self }) |
50 | } |
51 | } |
52 | |
53 | struct DateTimeVisitor; |
54 | |
55 | impl de::Visitor<'_> for DateTimeVisitor { |
56 | type Value = DateTime<FixedOffset>; |
57 | |
58 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
59 | formatter.write_str(data:"an RFC 3339 formatted date and time string" ) |
60 | } |
61 | |
62 | fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> |
63 | where |
64 | E: de::Error, |
65 | { |
66 | value.parse().map_err(E::custom) |
67 | } |
68 | } |
69 | |
70 | /// Deserialize an RFC 3339 formatted string into a `DateTime<FixedOffset>` |
71 | /// |
72 | /// As an extension to RFC 3339 this can deserialize to `DateTime`s outside the range of 0-9999 |
73 | /// years using an ISO 8601 syntax (which prepends an `-` or `+`). |
74 | /// |
75 | /// See [the `serde` module](crate::serde) for alternate deserialization formats. |
76 | impl<'de> de::Deserialize<'de> for DateTime<FixedOffset> { |
77 | fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> |
78 | where |
79 | D: de::Deserializer<'de>, |
80 | { |
81 | deserializer.deserialize_str(visitor:DateTimeVisitor) |
82 | } |
83 | } |
84 | |
85 | /// Deserialize an RFC 3339 formatted string into a `DateTime<Utc>` |
86 | /// |
87 | /// If the value contains an offset from UTC that is not zero, the value will be converted to UTC. |
88 | /// |
89 | /// As an extension to RFC 3339 this can deserialize to `DateTime`s outside the range of 0-9999 |
90 | /// years using an ISO 8601 syntax (which prepends an `-` or `+`). |
91 | /// |
92 | /// See [the `serde` module](crate::serde) for alternate deserialization formats. |
93 | impl<'de> de::Deserialize<'de> for DateTime<Utc> { |
94 | fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> |
95 | where |
96 | D: de::Deserializer<'de>, |
97 | { |
98 | deserializer.deserialize_str(DateTimeVisitor).map(|dt: DateTime| dt.with_timezone(&Utc)) |
99 | } |
100 | } |
101 | |
102 | /// Deserialize an RFC 3339 formatted string into a `DateTime<Local>` |
103 | /// |
104 | /// The value will remain the same instant in UTC, but the offset will be recalculated to match |
105 | /// that of the `Local` platform time zone. |
106 | /// |
107 | /// As an extension to RFC 3339 this can deserialize to `DateTime`s outside the range of 0-9999 |
108 | /// years using an ISO 8601 syntax (which prepends an `-` or `+`). |
109 | /// |
110 | /// See [the `serde` module](crate::serde) for alternate deserialization formats. |
111 | #[cfg (feature = "clock" )] |
112 | impl<'de> de::Deserialize<'de> for DateTime<Local> { |
113 | fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> |
114 | where |
115 | D: de::Deserializer<'de>, |
116 | { |
117 | deserializer.deserialize_str(DateTimeVisitor).map(|dt: DateTime| dt.with_timezone(&Local)) |
118 | } |
119 | } |
120 | |
121 | /// Ser/de to/from timestamps in nanoseconds |
122 | /// |
123 | /// Intended for use with `serde`'s `with` attribute. |
124 | /// |
125 | /// # Example: |
126 | /// |
127 | /// ```rust |
128 | /// # use chrono::{DateTime, Utc, NaiveDate}; |
129 | /// # use serde_derive::{Deserialize, Serialize}; |
130 | /// use chrono::serde::ts_nanoseconds; |
131 | /// #[derive(Deserialize, Serialize)] |
132 | /// struct S { |
133 | /// #[serde(with = "ts_nanoseconds" )] |
134 | /// time: DateTime<Utc>, |
135 | /// } |
136 | /// |
137 | /// let time = NaiveDate::from_ymd_opt(2018, 5, 17) |
138 | /// .unwrap() |
139 | /// .and_hms_nano_opt(02, 04, 59, 918355733) |
140 | /// .unwrap() |
141 | /// .and_utc(); |
142 | /// let my_s = S { time: time.clone() }; |
143 | /// |
144 | /// let as_string = serde_json::to_string(&my_s)?; |
145 | /// assert_eq!(as_string, r#"{"time":1526522699918355733}"# ); |
146 | /// let my_s: S = serde_json::from_str(&as_string)?; |
147 | /// assert_eq!(my_s.time, time); |
148 | /// # Ok::<(), serde_json::Error>(()) |
149 | /// ``` |
150 | pub mod ts_nanoseconds { |
151 | use core::fmt; |
152 | use serde::{de, ser}; |
153 | |
154 | use crate::serde::invalid_ts; |
155 | use crate::{DateTime, Utc}; |
156 | |
157 | use super::NanoSecondsTimestampVisitor; |
158 | |
159 | /// Serialize a UTC datetime into an integer number of nanoseconds since the epoch |
160 | /// |
161 | /// Intended for use with `serde`s `serialize_with` attribute. |
162 | /// |
163 | /// # Errors |
164 | /// |
165 | /// An `i64` with nanosecond precision can span a range of ~584 years. This function returns an |
166 | /// error on an out of range `DateTime`. |
167 | /// |
168 | /// The dates that can be represented as nanoseconds are between 1677-09-21T00:12:44.0 and |
169 | /// 2262-04-11T23:47:16.854775804. |
170 | /// |
171 | /// # Example: |
172 | /// |
173 | /// ```rust |
174 | /// # use chrono::{DateTime, Utc, NaiveDate}; |
175 | /// # use serde_derive::Serialize; |
176 | /// use chrono::serde::ts_nanoseconds::serialize as to_nano_ts; |
177 | /// #[derive(Serialize)] |
178 | /// struct S { |
179 | /// #[serde(serialize_with = "to_nano_ts" )] |
180 | /// time: DateTime<Utc>, |
181 | /// } |
182 | /// |
183 | /// let my_s = S { |
184 | /// time: NaiveDate::from_ymd_opt(2018, 5, 17) |
185 | /// .unwrap() |
186 | /// .and_hms_nano_opt(02, 04, 59, 918355733) |
187 | /// .unwrap() |
188 | /// .and_utc(), |
189 | /// }; |
190 | /// let as_string = serde_json::to_string(&my_s)?; |
191 | /// assert_eq!(as_string, r#"{"time":1526522699918355733}"# ); |
192 | /// # Ok::<(), serde_json::Error>(()) |
193 | /// ``` |
194 | pub fn serialize<S>(dt: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error> |
195 | where |
196 | S: ser::Serializer, |
197 | { |
198 | serializer.serialize_i64(dt.timestamp_nanos_opt().ok_or(ser::Error::custom( |
199 | "value out of range for a timestamp with nanosecond precision" , |
200 | ))?) |
201 | } |
202 | |
203 | /// Deserialize a [`DateTime`] from a nanosecond timestamp |
204 | /// |
205 | /// Intended for use with `serde`s `deserialize_with` attribute. |
206 | /// |
207 | /// # Example: |
208 | /// |
209 | /// ```rust |
210 | /// # use chrono::{DateTime, TimeZone, Utc}; |
211 | /// # use serde_derive::Deserialize; |
212 | /// use chrono::serde::ts_nanoseconds::deserialize as from_nano_ts; |
213 | /// #[derive(Debug, PartialEq, Deserialize)] |
214 | /// struct S { |
215 | /// #[serde(deserialize_with = "from_nano_ts" )] |
216 | /// time: DateTime<Utc>, |
217 | /// } |
218 | /// |
219 | /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"# )?; |
220 | /// assert_eq!(my_s, S { time: Utc.timestamp_opt(1526522699, 918355733).unwrap() }); |
221 | /// |
222 | /// let my_s: S = serde_json::from_str(r#"{ "time": -1 }"# )?; |
223 | /// assert_eq!(my_s, S { time: Utc.timestamp_opt(-1, 999_999_999).unwrap() }); |
224 | /// # Ok::<(), serde_json::Error>(()) |
225 | /// ``` |
226 | pub fn deserialize<'de, D>(d: D) -> Result<DateTime<Utc>, D::Error> |
227 | where |
228 | D: de::Deserializer<'de>, |
229 | { |
230 | d.deserialize_i64(NanoSecondsTimestampVisitor) |
231 | } |
232 | |
233 | impl de::Visitor<'_> for NanoSecondsTimestampVisitor { |
234 | type Value = DateTime<Utc>; |
235 | |
236 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
237 | formatter.write_str("a unix timestamp in nanoseconds" ) |
238 | } |
239 | |
240 | /// Deserialize a timestamp in nanoseconds since the epoch |
241 | fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E> |
242 | where |
243 | E: de::Error, |
244 | { |
245 | DateTime::from_timestamp( |
246 | value.div_euclid(1_000_000_000), |
247 | (value.rem_euclid(1_000_000_000)) as u32, |
248 | ) |
249 | .ok_or_else(|| invalid_ts(value)) |
250 | } |
251 | |
252 | /// Deserialize a timestamp in nanoseconds since the epoch |
253 | fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E> |
254 | where |
255 | E: de::Error, |
256 | { |
257 | DateTime::from_timestamp((value / 1_000_000_000) as i64, (value % 1_000_000_000) as u32) |
258 | .ok_or_else(|| invalid_ts(value)) |
259 | } |
260 | } |
261 | } |
262 | |
263 | /// Ser/de to/from optional timestamps in nanoseconds |
264 | /// |
265 | /// Intended for use with `serde`'s `with` attribute. |
266 | /// |
267 | /// # Example: |
268 | /// |
269 | /// ```rust |
270 | /// # use chrono::{DateTime, Utc, NaiveDate}; |
271 | /// # use serde_derive::{Deserialize, Serialize}; |
272 | /// use chrono::serde::ts_nanoseconds_option; |
273 | /// #[derive(Deserialize, Serialize)] |
274 | /// struct S { |
275 | /// #[serde(with = "ts_nanoseconds_option" )] |
276 | /// time: Option<DateTime<Utc>>, |
277 | /// } |
278 | /// |
279 | /// let time = Some( |
280 | /// NaiveDate::from_ymd_opt(2018, 5, 17) |
281 | /// .unwrap() |
282 | /// .and_hms_nano_opt(02, 04, 59, 918355733) |
283 | /// .unwrap() |
284 | /// .and_utc(), |
285 | /// ); |
286 | /// let my_s = S { time: time.clone() }; |
287 | /// |
288 | /// let as_string = serde_json::to_string(&my_s)?; |
289 | /// assert_eq!(as_string, r#"{"time":1526522699918355733}"# ); |
290 | /// let my_s: S = serde_json::from_str(&as_string)?; |
291 | /// assert_eq!(my_s.time, time); |
292 | /// # Ok::<(), serde_json::Error>(()) |
293 | /// ``` |
294 | pub mod ts_nanoseconds_option { |
295 | use core::fmt; |
296 | use serde::{de, ser}; |
297 | |
298 | use crate::{DateTime, Utc}; |
299 | |
300 | use super::NanoSecondsTimestampVisitor; |
301 | |
302 | /// Serialize a UTC datetime into an integer number of nanoseconds since the epoch or none |
303 | /// |
304 | /// Intended for use with `serde`s `serialize_with` attribute. |
305 | /// |
306 | /// # Errors |
307 | /// |
308 | /// An `i64` with nanosecond precision can span a range of ~584 years. This function returns an |
309 | /// error on an out of range `DateTime`. |
310 | /// |
311 | /// The dates that can be represented as nanoseconds are between 1677-09-21T00:12:44.0 and |
312 | /// 2262-04-11T23:47:16.854775804. |
313 | /// |
314 | /// # Example: |
315 | /// |
316 | /// ```rust |
317 | /// # use chrono::{DateTime, Utc, NaiveDate}; |
318 | /// # use serde_derive::Serialize; |
319 | /// use chrono::serde::ts_nanoseconds_option::serialize as to_nano_tsopt; |
320 | /// #[derive(Serialize)] |
321 | /// struct S { |
322 | /// #[serde(serialize_with = "to_nano_tsopt" )] |
323 | /// time: Option<DateTime<Utc>>, |
324 | /// } |
325 | /// |
326 | /// let my_s = S { |
327 | /// time: Some( |
328 | /// NaiveDate::from_ymd_opt(2018, 5, 17) |
329 | /// .unwrap() |
330 | /// .and_hms_nano_opt(02, 04, 59, 918355733) |
331 | /// .unwrap() |
332 | /// .and_utc(), |
333 | /// ), |
334 | /// }; |
335 | /// let as_string = serde_json::to_string(&my_s)?; |
336 | /// assert_eq!(as_string, r#"{"time":1526522699918355733}"# ); |
337 | /// # Ok::<(), serde_json::Error>(()) |
338 | /// ``` |
339 | pub fn serialize<S>(opt: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error> |
340 | where |
341 | S: ser::Serializer, |
342 | { |
343 | match *opt { |
344 | Some(ref dt) => serializer.serialize_some(&dt.timestamp_nanos_opt().ok_or( |
345 | ser::Error::custom("value out of range for a timestamp with nanosecond precision" ), |
346 | )?), |
347 | None => serializer.serialize_none(), |
348 | } |
349 | } |
350 | |
351 | /// Deserialize a `DateTime` from a nanosecond timestamp or none |
352 | /// |
353 | /// Intended for use with `serde`s `deserialize_with` attribute. |
354 | /// |
355 | /// # Example: |
356 | /// |
357 | /// ```rust |
358 | /// # use chrono::{DateTime, TimeZone, Utc}; |
359 | /// # use serde_derive::Deserialize; |
360 | /// use chrono::serde::ts_nanoseconds_option::deserialize as from_nano_tsopt; |
361 | /// #[derive(Debug, PartialEq, Deserialize)] |
362 | /// struct S { |
363 | /// #[serde(deserialize_with = "from_nano_tsopt" )] |
364 | /// time: Option<DateTime<Utc>>, |
365 | /// } |
366 | /// |
367 | /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"# )?; |
368 | /// assert_eq!(my_s, S { time: Utc.timestamp_opt(1526522699, 918355733).single() }); |
369 | /// # Ok::<(), serde_json::Error>(()) |
370 | /// ``` |
371 | pub fn deserialize<'de, D>(d: D) -> Result<Option<DateTime<Utc>>, D::Error> |
372 | where |
373 | D: de::Deserializer<'de>, |
374 | { |
375 | d.deserialize_option(OptionNanoSecondsTimestampVisitor) |
376 | } |
377 | |
378 | struct OptionNanoSecondsTimestampVisitor; |
379 | |
380 | impl<'de> de::Visitor<'de> for OptionNanoSecondsTimestampVisitor { |
381 | type Value = Option<DateTime<Utc>>; |
382 | |
383 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
384 | formatter.write_str("a unix timestamp in nanoseconds or none" ) |
385 | } |
386 | |
387 | /// Deserialize a timestamp in nanoseconds since the epoch |
388 | fn visit_some<D>(self, d: D) -> Result<Self::Value, D::Error> |
389 | where |
390 | D: de::Deserializer<'de>, |
391 | { |
392 | d.deserialize_i64(NanoSecondsTimestampVisitor).map(Some) |
393 | } |
394 | |
395 | /// Deserialize a timestamp in nanoseconds since the epoch |
396 | fn visit_none<E>(self) -> Result<Self::Value, E> |
397 | where |
398 | E: de::Error, |
399 | { |
400 | Ok(None) |
401 | } |
402 | |
403 | /// Deserialize a timestamp in nanoseconds since the epoch |
404 | fn visit_unit<E>(self) -> Result<Self::Value, E> |
405 | where |
406 | E: de::Error, |
407 | { |
408 | Ok(None) |
409 | } |
410 | } |
411 | } |
412 | |
413 | /// Ser/de to/from timestamps in microseconds |
414 | /// |
415 | /// Intended for use with `serde`'s `with` attribute. |
416 | /// |
417 | /// # Example: |
418 | /// |
419 | /// ```rust |
420 | /// # use chrono::{DateTime, Utc, NaiveDate}; |
421 | /// # use serde_derive::{Deserialize, Serialize}; |
422 | /// use chrono::serde::ts_microseconds; |
423 | /// #[derive(Deserialize, Serialize)] |
424 | /// struct S { |
425 | /// #[serde(with = "ts_microseconds" )] |
426 | /// time: DateTime<Utc>, |
427 | /// } |
428 | /// |
429 | /// let time = NaiveDate::from_ymd_opt(2018, 5, 17) |
430 | /// .unwrap() |
431 | /// .and_hms_micro_opt(02, 04, 59, 918355) |
432 | /// .unwrap() |
433 | /// .and_utc(); |
434 | /// let my_s = S { time: time.clone() }; |
435 | /// |
436 | /// let as_string = serde_json::to_string(&my_s)?; |
437 | /// assert_eq!(as_string, r#"{"time":1526522699918355}"# ); |
438 | /// let my_s: S = serde_json::from_str(&as_string)?; |
439 | /// assert_eq!(my_s.time, time); |
440 | /// # Ok::<(), serde_json::Error>(()) |
441 | /// ``` |
442 | pub mod ts_microseconds { |
443 | use core::fmt; |
444 | use serde::{de, ser}; |
445 | |
446 | use crate::serde::invalid_ts; |
447 | use crate::{DateTime, Utc}; |
448 | |
449 | use super::MicroSecondsTimestampVisitor; |
450 | |
451 | /// Serialize a UTC datetime into an integer number of microseconds since the epoch |
452 | /// |
453 | /// Intended for use with `serde`s `serialize_with` attribute. |
454 | /// |
455 | /// # Example: |
456 | /// |
457 | /// ```rust |
458 | /// # use chrono::{DateTime, Utc, NaiveDate}; |
459 | /// # use serde_derive::Serialize; |
460 | /// use chrono::serde::ts_microseconds::serialize as to_micro_ts; |
461 | /// #[derive(Serialize)] |
462 | /// struct S { |
463 | /// #[serde(serialize_with = "to_micro_ts" )] |
464 | /// time: DateTime<Utc>, |
465 | /// } |
466 | /// |
467 | /// let my_s = S { |
468 | /// time: NaiveDate::from_ymd_opt(2018, 5, 17) |
469 | /// .unwrap() |
470 | /// .and_hms_micro_opt(02, 04, 59, 918355) |
471 | /// .unwrap() |
472 | /// .and_utc(), |
473 | /// }; |
474 | /// let as_string = serde_json::to_string(&my_s)?; |
475 | /// assert_eq!(as_string, r#"{"time":1526522699918355}"# ); |
476 | /// # Ok::<(), serde_json::Error>(()) |
477 | /// ``` |
478 | pub fn serialize<S>(dt: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error> |
479 | where |
480 | S: ser::Serializer, |
481 | { |
482 | serializer.serialize_i64(dt.timestamp_micros()) |
483 | } |
484 | |
485 | /// Deserialize a `DateTime` from a microsecond timestamp |
486 | /// |
487 | /// Intended for use with `serde`s `deserialize_with` attribute. |
488 | /// |
489 | /// # Example: |
490 | /// |
491 | /// ```rust |
492 | /// # use chrono::{DateTime, TimeZone, Utc}; |
493 | /// # use serde_derive::Deserialize; |
494 | /// use chrono::serde::ts_microseconds::deserialize as from_micro_ts; |
495 | /// #[derive(Debug, PartialEq, Deserialize)] |
496 | /// struct S { |
497 | /// #[serde(deserialize_with = "from_micro_ts" )] |
498 | /// time: DateTime<Utc>, |
499 | /// } |
500 | /// |
501 | /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355 }"# )?; |
502 | /// assert_eq!(my_s, S { time: Utc.timestamp_opt(1526522699, 918355000).unwrap() }); |
503 | /// |
504 | /// let my_s: S = serde_json::from_str(r#"{ "time": -1 }"# )?; |
505 | /// assert_eq!(my_s, S { time: Utc.timestamp_opt(-1, 999_999_000).unwrap() }); |
506 | /// # Ok::<(), serde_json::Error>(()) |
507 | /// ``` |
508 | pub fn deserialize<'de, D>(d: D) -> Result<DateTime<Utc>, D::Error> |
509 | where |
510 | D: de::Deserializer<'de>, |
511 | { |
512 | d.deserialize_i64(MicroSecondsTimestampVisitor) |
513 | } |
514 | |
515 | impl de::Visitor<'_> for MicroSecondsTimestampVisitor { |
516 | type Value = DateTime<Utc>; |
517 | |
518 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
519 | formatter.write_str("a unix timestamp in microseconds" ) |
520 | } |
521 | |
522 | /// Deserialize a timestamp in milliseconds since the epoch |
523 | fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E> |
524 | where |
525 | E: de::Error, |
526 | { |
527 | DateTime::from_timestamp( |
528 | value.div_euclid(1_000_000), |
529 | (value.rem_euclid(1_000_000) * 1000) as u32, |
530 | ) |
531 | .ok_or_else(|| invalid_ts(value)) |
532 | } |
533 | |
534 | /// Deserialize a timestamp in milliseconds since the epoch |
535 | fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E> |
536 | where |
537 | E: de::Error, |
538 | { |
539 | DateTime::from_timestamp( |
540 | (value / 1_000_000) as i64, |
541 | ((value % 1_000_000) * 1_000) as u32, |
542 | ) |
543 | .ok_or_else(|| invalid_ts(value)) |
544 | } |
545 | } |
546 | } |
547 | |
548 | /// Ser/de to/from optional timestamps in microseconds |
549 | /// |
550 | /// Intended for use with `serde`'s `with` attribute. |
551 | /// |
552 | /// # Example: |
553 | /// |
554 | /// ```rust |
555 | /// # use chrono::{DateTime, Utc, NaiveDate}; |
556 | /// # use serde_derive::{Deserialize, Serialize}; |
557 | /// use chrono::serde::ts_microseconds_option; |
558 | /// #[derive(Deserialize, Serialize)] |
559 | /// struct S { |
560 | /// #[serde(with = "ts_microseconds_option" )] |
561 | /// time: Option<DateTime<Utc>>, |
562 | /// } |
563 | /// |
564 | /// let time = Some( |
565 | /// NaiveDate::from_ymd_opt(2018, 5, 17) |
566 | /// .unwrap() |
567 | /// .and_hms_micro_opt(02, 04, 59, 918355) |
568 | /// .unwrap() |
569 | /// .and_utc(), |
570 | /// ); |
571 | /// let my_s = S { time: time.clone() }; |
572 | /// |
573 | /// let as_string = serde_json::to_string(&my_s)?; |
574 | /// assert_eq!(as_string, r#"{"time":1526522699918355}"# ); |
575 | /// let my_s: S = serde_json::from_str(&as_string)?; |
576 | /// assert_eq!(my_s.time, time); |
577 | /// # Ok::<(), serde_json::Error>(()) |
578 | /// ``` |
579 | pub mod ts_microseconds_option { |
580 | use core::fmt; |
581 | use serde::{de, ser}; |
582 | |
583 | use super::MicroSecondsTimestampVisitor; |
584 | use crate::{DateTime, Utc}; |
585 | |
586 | /// Serialize a UTC datetime into an integer number of microseconds since the epoch or none |
587 | /// |
588 | /// Intended for use with `serde`s `serialize_with` attribute. |
589 | /// |
590 | /// # Example: |
591 | /// |
592 | /// ```rust |
593 | /// # use chrono::{DateTime, Utc, NaiveDate}; |
594 | /// # use serde_derive::Serialize; |
595 | /// use chrono::serde::ts_microseconds_option::serialize as to_micro_tsopt; |
596 | /// #[derive(Serialize)] |
597 | /// struct S { |
598 | /// #[serde(serialize_with = "to_micro_tsopt" )] |
599 | /// time: Option<DateTime<Utc>>, |
600 | /// } |
601 | /// |
602 | /// let my_s = S { |
603 | /// time: Some( |
604 | /// NaiveDate::from_ymd_opt(2018, 5, 17) |
605 | /// .unwrap() |
606 | /// .and_hms_micro_opt(02, 04, 59, 918355) |
607 | /// .unwrap() |
608 | /// .and_utc(), |
609 | /// ), |
610 | /// }; |
611 | /// let as_string = serde_json::to_string(&my_s)?; |
612 | /// assert_eq!(as_string, r#"{"time":1526522699918355}"# ); |
613 | /// # Ok::<(), serde_json::Error>(()) |
614 | /// ``` |
615 | pub fn serialize<S>(opt: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error> |
616 | where |
617 | S: ser::Serializer, |
618 | { |
619 | match *opt { |
620 | Some(ref dt) => serializer.serialize_some(&dt.timestamp_micros()), |
621 | None => serializer.serialize_none(), |
622 | } |
623 | } |
624 | |
625 | /// Deserialize a `DateTime` from a microsecond timestamp or none |
626 | /// |
627 | /// Intended for use with `serde`s `deserialize_with` attribute. |
628 | /// |
629 | /// # Example: |
630 | /// |
631 | /// ```rust |
632 | /// # use chrono::{DateTime, TimeZone, Utc}; |
633 | /// # use serde_derive::Deserialize; |
634 | /// use chrono::serde::ts_microseconds_option::deserialize as from_micro_tsopt; |
635 | /// #[derive(Debug, PartialEq, Deserialize)] |
636 | /// struct S { |
637 | /// #[serde(deserialize_with = "from_micro_tsopt" )] |
638 | /// time: Option<DateTime<Utc>>, |
639 | /// } |
640 | /// |
641 | /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355 }"# )?; |
642 | /// assert_eq!(my_s, S { time: Utc.timestamp_opt(1526522699, 918355000).single() }); |
643 | /// # Ok::<(), serde_json::Error>(()) |
644 | /// ``` |
645 | pub fn deserialize<'de, D>(d: D) -> Result<Option<DateTime<Utc>>, D::Error> |
646 | where |
647 | D: de::Deserializer<'de>, |
648 | { |
649 | d.deserialize_option(OptionMicroSecondsTimestampVisitor) |
650 | } |
651 | |
652 | struct OptionMicroSecondsTimestampVisitor; |
653 | |
654 | impl<'de> de::Visitor<'de> for OptionMicroSecondsTimestampVisitor { |
655 | type Value = Option<DateTime<Utc>>; |
656 | |
657 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
658 | formatter.write_str("a unix timestamp in microseconds or none" ) |
659 | } |
660 | |
661 | /// Deserialize a timestamp in microseconds since the epoch |
662 | fn visit_some<D>(self, d: D) -> Result<Self::Value, D::Error> |
663 | where |
664 | D: de::Deserializer<'de>, |
665 | { |
666 | d.deserialize_i64(MicroSecondsTimestampVisitor).map(Some) |
667 | } |
668 | |
669 | /// Deserialize a timestamp in microseconds since the epoch |
670 | fn visit_none<E>(self) -> Result<Self::Value, E> |
671 | where |
672 | E: de::Error, |
673 | { |
674 | Ok(None) |
675 | } |
676 | |
677 | /// Deserialize a timestamp in microseconds since the epoch |
678 | fn visit_unit<E>(self) -> Result<Self::Value, E> |
679 | where |
680 | E: de::Error, |
681 | { |
682 | Ok(None) |
683 | } |
684 | } |
685 | } |
686 | |
687 | /// Ser/de to/from timestamps in milliseconds |
688 | /// |
689 | /// Intended for use with `serde`s `with` attribute. |
690 | /// |
691 | /// # Example |
692 | /// |
693 | /// ```rust |
694 | /// # use chrono::{DateTime, Utc, NaiveDate}; |
695 | /// # use serde_derive::{Deserialize, Serialize}; |
696 | /// use chrono::serde::ts_milliseconds; |
697 | /// #[derive(Deserialize, Serialize)] |
698 | /// struct S { |
699 | /// #[serde(with = "ts_milliseconds" )] |
700 | /// time: DateTime<Utc>, |
701 | /// } |
702 | /// |
703 | /// let time = NaiveDate::from_ymd_opt(2018, 5, 17) |
704 | /// .unwrap() |
705 | /// .and_hms_milli_opt(02, 04, 59, 918) |
706 | /// .unwrap() |
707 | /// .and_utc(); |
708 | /// let my_s = S { time: time.clone() }; |
709 | /// |
710 | /// let as_string = serde_json::to_string(&my_s)?; |
711 | /// assert_eq!(as_string, r#"{"time":1526522699918}"# ); |
712 | /// let my_s: S = serde_json::from_str(&as_string)?; |
713 | /// assert_eq!(my_s.time, time); |
714 | /// # Ok::<(), serde_json::Error>(()) |
715 | /// ``` |
716 | pub mod ts_milliseconds { |
717 | use core::fmt; |
718 | use serde::{de, ser}; |
719 | |
720 | use crate::serde::invalid_ts; |
721 | use crate::{DateTime, Utc}; |
722 | |
723 | use super::MilliSecondsTimestampVisitor; |
724 | |
725 | /// Serialize a UTC datetime into an integer number of milliseconds since the epoch |
726 | /// |
727 | /// Intended for use with `serde`s `serialize_with` attribute. |
728 | /// |
729 | /// # Example: |
730 | /// |
731 | /// ```rust |
732 | /// # use chrono::{DateTime, Utc, NaiveDate}; |
733 | /// # use serde_derive::Serialize; |
734 | /// use chrono::serde::ts_milliseconds::serialize as to_milli_ts; |
735 | /// #[derive(Serialize)] |
736 | /// struct S { |
737 | /// #[serde(serialize_with = "to_milli_ts" )] |
738 | /// time: DateTime<Utc>, |
739 | /// } |
740 | /// |
741 | /// let my_s = S { |
742 | /// time: NaiveDate::from_ymd_opt(2018, 5, 17) |
743 | /// .unwrap() |
744 | /// .and_hms_milli_opt(02, 04, 59, 918) |
745 | /// .unwrap() |
746 | /// .and_utc(), |
747 | /// }; |
748 | /// let as_string = serde_json::to_string(&my_s)?; |
749 | /// assert_eq!(as_string, r#"{"time":1526522699918}"# ); |
750 | /// # Ok::<(), serde_json::Error>(()) |
751 | /// ``` |
752 | pub fn serialize<S>(dt: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error> |
753 | where |
754 | S: ser::Serializer, |
755 | { |
756 | serializer.serialize_i64(dt.timestamp_millis()) |
757 | } |
758 | |
759 | /// Deserialize a `DateTime` from a millisecond timestamp |
760 | /// |
761 | /// Intended for use with `serde`s `deserialize_with` attribute. |
762 | /// |
763 | /// # Example: |
764 | /// |
765 | /// ```rust |
766 | /// # use chrono::{DateTime, TimeZone, Utc}; |
767 | /// # use serde_derive::Deserialize; |
768 | /// use chrono::serde::ts_milliseconds::deserialize as from_milli_ts; |
769 | /// #[derive(Debug, PartialEq, Deserialize)] |
770 | /// struct S { |
771 | /// #[serde(deserialize_with = "from_milli_ts" )] |
772 | /// time: DateTime<Utc>, |
773 | /// } |
774 | /// |
775 | /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918 }"# )?; |
776 | /// assert_eq!(my_s, S { time: Utc.timestamp_opt(1526522699, 918000000).unwrap() }); |
777 | /// |
778 | /// let my_s: S = serde_json::from_str(r#"{ "time": -1 }"# )?; |
779 | /// assert_eq!(my_s, S { time: Utc.timestamp_opt(-1, 999_000_000).unwrap() }); |
780 | /// # Ok::<(), serde_json::Error>(()) |
781 | /// ``` |
782 | pub fn deserialize<'de, D>(d: D) -> Result<DateTime<Utc>, D::Error> |
783 | where |
784 | D: de::Deserializer<'de>, |
785 | { |
786 | d.deserialize_i64(MilliSecondsTimestampVisitor).map(|dt| dt.with_timezone(&Utc)) |
787 | } |
788 | |
789 | impl de::Visitor<'_> for MilliSecondsTimestampVisitor { |
790 | type Value = DateTime<Utc>; |
791 | |
792 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
793 | formatter.write_str("a unix timestamp in milliseconds" ) |
794 | } |
795 | |
796 | /// Deserialize a timestamp in milliseconds since the epoch |
797 | fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E> |
798 | where |
799 | E: de::Error, |
800 | { |
801 | DateTime::from_timestamp_millis(value).ok_or_else(|| invalid_ts(value)) |
802 | } |
803 | |
804 | /// Deserialize a timestamp in milliseconds since the epoch |
805 | fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E> |
806 | where |
807 | E: de::Error, |
808 | { |
809 | DateTime::from_timestamp((value / 1000) as i64, ((value % 1000) * 1_000_000) as u32) |
810 | .ok_or_else(|| invalid_ts(value)) |
811 | } |
812 | } |
813 | } |
814 | |
815 | /// Ser/de to/from optional timestamps in milliseconds |
816 | /// |
817 | /// Intended for use with `serde`s `with` attribute. |
818 | /// |
819 | /// # Example |
820 | /// |
821 | /// ```rust |
822 | /// # use chrono::{DateTime, Utc, NaiveDate}; |
823 | /// # use serde_derive::{Deserialize, Serialize}; |
824 | /// use chrono::serde::ts_milliseconds_option; |
825 | /// #[derive(Deserialize, Serialize)] |
826 | /// struct S { |
827 | /// #[serde(with = "ts_milliseconds_option" )] |
828 | /// time: Option<DateTime<Utc>>, |
829 | /// } |
830 | /// |
831 | /// let time = Some( |
832 | /// NaiveDate::from_ymd_opt(2018, 5, 17) |
833 | /// .unwrap() |
834 | /// .and_hms_milli_opt(02, 04, 59, 918) |
835 | /// .unwrap() |
836 | /// .and_utc(), |
837 | /// ); |
838 | /// let my_s = S { time: time.clone() }; |
839 | /// |
840 | /// let as_string = serde_json::to_string(&my_s)?; |
841 | /// assert_eq!(as_string, r#"{"time":1526522699918}"# ); |
842 | /// let my_s: S = serde_json::from_str(&as_string)?; |
843 | /// assert_eq!(my_s.time, time); |
844 | /// # Ok::<(), serde_json::Error>(()) |
845 | /// ``` |
846 | pub mod ts_milliseconds_option { |
847 | use core::fmt; |
848 | use serde::{de, ser}; |
849 | |
850 | use super::MilliSecondsTimestampVisitor; |
851 | use crate::{DateTime, Utc}; |
852 | |
853 | /// Serialize a UTC datetime into an integer number of milliseconds since the epoch or none |
854 | /// |
855 | /// Intended for use with `serde`s `serialize_with` attribute. |
856 | /// |
857 | /// # Example: |
858 | /// |
859 | /// ```rust |
860 | /// # use chrono::{DateTime, Utc, NaiveDate}; |
861 | /// # use serde_derive::Serialize; |
862 | /// use chrono::serde::ts_milliseconds_option::serialize as to_milli_tsopt; |
863 | /// #[derive(Serialize)] |
864 | /// struct S { |
865 | /// #[serde(serialize_with = "to_milli_tsopt" )] |
866 | /// time: Option<DateTime<Utc>>, |
867 | /// } |
868 | /// |
869 | /// let my_s = S { |
870 | /// time: Some( |
871 | /// NaiveDate::from_ymd_opt(2018, 5, 17) |
872 | /// .unwrap() |
873 | /// .and_hms_milli_opt(02, 04, 59, 918) |
874 | /// .unwrap() |
875 | /// .and_utc(), |
876 | /// ), |
877 | /// }; |
878 | /// let as_string = serde_json::to_string(&my_s)?; |
879 | /// assert_eq!(as_string, r#"{"time":1526522699918}"# ); |
880 | /// # Ok::<(), serde_json::Error>(()) |
881 | /// ``` |
882 | pub fn serialize<S>(opt: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error> |
883 | where |
884 | S: ser::Serializer, |
885 | { |
886 | match *opt { |
887 | Some(ref dt) => serializer.serialize_some(&dt.timestamp_millis()), |
888 | None => serializer.serialize_none(), |
889 | } |
890 | } |
891 | |
892 | /// Deserialize a `DateTime` from a millisecond timestamp or none |
893 | /// |
894 | /// Intended for use with `serde`s `deserialize_with` attribute. |
895 | /// |
896 | /// # Example: |
897 | /// |
898 | /// ```rust |
899 | /// # use chrono::{TimeZone, DateTime, Utc}; |
900 | /// # use serde_derive::Deserialize; |
901 | /// use chrono::serde::ts_milliseconds_option::deserialize as from_milli_tsopt; |
902 | /// |
903 | /// #[derive(Deserialize, PartialEq, Debug)] |
904 | /// #[serde(untagged)] |
905 | /// enum E<T> { |
906 | /// V(T), |
907 | /// } |
908 | /// |
909 | /// #[derive(Deserialize, PartialEq, Debug)] |
910 | /// struct S { |
911 | /// #[serde(default, deserialize_with = "from_milli_tsopt" )] |
912 | /// time: Option<DateTime<Utc>>, |
913 | /// } |
914 | /// |
915 | /// let my_s: E<S> = serde_json::from_str(r#"{ "time": 1526522699918 }"# )?; |
916 | /// assert_eq!(my_s, E::V(S { time: Some(Utc.timestamp_opt(1526522699, 918000000).unwrap()) })); |
917 | /// let s: E<S> = serde_json::from_str(r#"{ "time": null }"# )?; |
918 | /// assert_eq!(s, E::V(S { time: None })); |
919 | /// let t: E<S> = serde_json::from_str(r#"{}"# )?; |
920 | /// assert_eq!(t, E::V(S { time: None })); |
921 | /// # Ok::<(), serde_json::Error>(()) |
922 | /// ``` |
923 | pub fn deserialize<'de, D>(d: D) -> Result<Option<DateTime<Utc>>, D::Error> |
924 | where |
925 | D: de::Deserializer<'de>, |
926 | { |
927 | d.deserialize_option(OptionMilliSecondsTimestampVisitor) |
928 | .map(|opt| opt.map(|dt| dt.with_timezone(&Utc))) |
929 | } |
930 | |
931 | struct OptionMilliSecondsTimestampVisitor; |
932 | |
933 | impl<'de> de::Visitor<'de> for OptionMilliSecondsTimestampVisitor { |
934 | type Value = Option<DateTime<Utc>>; |
935 | |
936 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
937 | formatter.write_str("a unix timestamp in milliseconds or none" ) |
938 | } |
939 | |
940 | /// Deserialize a timestamp in milliseconds since the epoch |
941 | fn visit_some<D>(self, d: D) -> Result<Self::Value, D::Error> |
942 | where |
943 | D: de::Deserializer<'de>, |
944 | { |
945 | d.deserialize_i64(MilliSecondsTimestampVisitor).map(Some) |
946 | } |
947 | |
948 | /// Deserialize a timestamp in milliseconds since the epoch |
949 | fn visit_none<E>(self) -> Result<Self::Value, E> |
950 | where |
951 | E: de::Error, |
952 | { |
953 | Ok(None) |
954 | } |
955 | |
956 | /// Deserialize a timestamp in milliseconds since the epoch |
957 | fn visit_unit<E>(self) -> Result<Self::Value, E> |
958 | where |
959 | E: de::Error, |
960 | { |
961 | Ok(None) |
962 | } |
963 | } |
964 | } |
965 | |
966 | /// Ser/de to/from timestamps in seconds |
967 | /// |
968 | /// Intended for use with `serde`'s `with` attribute. |
969 | /// |
970 | /// # Example: |
971 | /// |
972 | /// ```rust |
973 | /// # use chrono::{TimeZone, DateTime, Utc}; |
974 | /// # use serde_derive::{Deserialize, Serialize}; |
975 | /// use chrono::serde::ts_seconds; |
976 | /// #[derive(Deserialize, Serialize)] |
977 | /// struct S { |
978 | /// #[serde(with = "ts_seconds" )] |
979 | /// time: DateTime<Utc>, |
980 | /// } |
981 | /// |
982 | /// let time = Utc.with_ymd_and_hms(2015, 5, 15, 10, 0, 0).unwrap(); |
983 | /// let my_s = S { time: time.clone() }; |
984 | /// |
985 | /// let as_string = serde_json::to_string(&my_s)?; |
986 | /// assert_eq!(as_string, r#"{"time":1431684000}"# ); |
987 | /// let my_s: S = serde_json::from_str(&as_string)?; |
988 | /// assert_eq!(my_s.time, time); |
989 | /// # Ok::<(), serde_json::Error>(()) |
990 | /// ``` |
991 | pub mod ts_seconds { |
992 | use core::fmt; |
993 | use serde::{de, ser}; |
994 | |
995 | use crate::serde::invalid_ts; |
996 | use crate::{DateTime, Utc}; |
997 | |
998 | use super::SecondsTimestampVisitor; |
999 | |
1000 | /// Serialize a UTC datetime into an integer number of seconds since the epoch |
1001 | /// |
1002 | /// Intended for use with `serde`s `serialize_with` attribute. |
1003 | /// |
1004 | /// # Example: |
1005 | /// |
1006 | /// ```rust |
1007 | /// # use chrono::{TimeZone, DateTime, Utc}; |
1008 | /// # use serde_derive::Serialize; |
1009 | /// use chrono::serde::ts_seconds::serialize as to_ts; |
1010 | /// #[derive(Serialize)] |
1011 | /// struct S { |
1012 | /// #[serde(serialize_with = "to_ts" )] |
1013 | /// time: DateTime<Utc>, |
1014 | /// } |
1015 | /// |
1016 | /// let my_s = S { time: Utc.with_ymd_and_hms(2015, 5, 15, 10, 0, 0).unwrap() }; |
1017 | /// let as_string = serde_json::to_string(&my_s)?; |
1018 | /// assert_eq!(as_string, r#"{"time":1431684000}"# ); |
1019 | /// # Ok::<(), serde_json::Error>(()) |
1020 | /// ``` |
1021 | pub fn serialize<S>(dt: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error> |
1022 | where |
1023 | S: ser::Serializer, |
1024 | { |
1025 | serializer.serialize_i64(dt.timestamp()) |
1026 | } |
1027 | |
1028 | /// Deserialize a `DateTime` from a seconds timestamp |
1029 | /// |
1030 | /// Intended for use with `serde`s `deserialize_with` attribute. |
1031 | /// |
1032 | /// # Example: |
1033 | /// |
1034 | /// ```rust |
1035 | /// # use chrono::{DateTime, TimeZone, Utc}; |
1036 | /// # use serde_derive::Deserialize; |
1037 | /// use chrono::serde::ts_seconds::deserialize as from_ts; |
1038 | /// #[derive(Debug, PartialEq, Deserialize)] |
1039 | /// struct S { |
1040 | /// #[serde(deserialize_with = "from_ts" )] |
1041 | /// time: DateTime<Utc>, |
1042 | /// } |
1043 | /// |
1044 | /// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"# )?; |
1045 | /// assert_eq!(my_s, S { time: Utc.timestamp_opt(1431684000, 0).unwrap() }); |
1046 | /// # Ok::<(), serde_json::Error>(()) |
1047 | /// ``` |
1048 | pub fn deserialize<'de, D>(d: D) -> Result<DateTime<Utc>, D::Error> |
1049 | where |
1050 | D: de::Deserializer<'de>, |
1051 | { |
1052 | d.deserialize_i64(SecondsTimestampVisitor) |
1053 | } |
1054 | |
1055 | impl de::Visitor<'_> for SecondsTimestampVisitor { |
1056 | type Value = DateTime<Utc>; |
1057 | |
1058 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
1059 | formatter.write_str("a unix timestamp in seconds" ) |
1060 | } |
1061 | |
1062 | /// Deserialize a timestamp in seconds since the epoch |
1063 | fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E> |
1064 | where |
1065 | E: de::Error, |
1066 | { |
1067 | DateTime::from_timestamp(value, 0).ok_or_else(|| invalid_ts(value)) |
1068 | } |
1069 | |
1070 | /// Deserialize a timestamp in seconds since the epoch |
1071 | fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E> |
1072 | where |
1073 | E: de::Error, |
1074 | { |
1075 | if value > i64::MAX as u64 { |
1076 | Err(invalid_ts(value)) |
1077 | } else { |
1078 | DateTime::from_timestamp(value as i64, 0).ok_or_else(|| invalid_ts(value)) |
1079 | } |
1080 | } |
1081 | } |
1082 | } |
1083 | |
1084 | /// Ser/de to/from optional timestamps in seconds |
1085 | /// |
1086 | /// Intended for use with `serde`'s `with` attribute. |
1087 | /// |
1088 | /// # Example: |
1089 | /// |
1090 | /// ```rust |
1091 | /// # use chrono::{TimeZone, DateTime, Utc}; |
1092 | /// # use serde_derive::{Deserialize, Serialize}; |
1093 | /// use chrono::serde::ts_seconds_option; |
1094 | /// #[derive(Deserialize, Serialize)] |
1095 | /// struct S { |
1096 | /// #[serde(with = "ts_seconds_option" )] |
1097 | /// time: Option<DateTime<Utc>>, |
1098 | /// } |
1099 | /// |
1100 | /// let time = Some(Utc.with_ymd_and_hms(2015, 5, 15, 10, 0, 0).unwrap()); |
1101 | /// let my_s = S { time: time.clone() }; |
1102 | /// |
1103 | /// let as_string = serde_json::to_string(&my_s)?; |
1104 | /// assert_eq!(as_string, r#"{"time":1431684000}"# ); |
1105 | /// let my_s: S = serde_json::from_str(&as_string)?; |
1106 | /// assert_eq!(my_s.time, time); |
1107 | /// # Ok::<(), serde_json::Error>(()) |
1108 | /// ``` |
1109 | pub mod ts_seconds_option { |
1110 | use core::fmt; |
1111 | use serde::{de, ser}; |
1112 | |
1113 | use super::SecondsTimestampVisitor; |
1114 | use crate::{DateTime, Utc}; |
1115 | |
1116 | /// Serialize a UTC datetime into an integer number of seconds since the epoch or none |
1117 | /// |
1118 | /// Intended for use with `serde`s `serialize_with` attribute. |
1119 | /// |
1120 | /// # Example: |
1121 | /// |
1122 | /// ```rust |
1123 | /// # use chrono::{TimeZone, DateTime, Utc}; |
1124 | /// # use serde_derive::Serialize; |
1125 | /// use chrono::serde::ts_seconds_option::serialize as to_tsopt; |
1126 | /// #[derive(Serialize)] |
1127 | /// struct S { |
1128 | /// #[serde(serialize_with = "to_tsopt" )] |
1129 | /// time: Option<DateTime<Utc>>, |
1130 | /// } |
1131 | /// |
1132 | /// let my_s = S { time: Some(Utc.with_ymd_and_hms(2015, 5, 15, 10, 0, 0).unwrap()) }; |
1133 | /// let as_string = serde_json::to_string(&my_s)?; |
1134 | /// assert_eq!(as_string, r#"{"time":1431684000}"# ); |
1135 | /// # Ok::<(), serde_json::Error>(()) |
1136 | /// ``` |
1137 | pub fn serialize<S>(opt: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error> |
1138 | where |
1139 | S: ser::Serializer, |
1140 | { |
1141 | match *opt { |
1142 | Some(ref dt) => serializer.serialize_some(&dt.timestamp()), |
1143 | None => serializer.serialize_none(), |
1144 | } |
1145 | } |
1146 | |
1147 | /// Deserialize a `DateTime` from a seconds timestamp or none |
1148 | /// |
1149 | /// Intended for use with `serde`s `deserialize_with` attribute. |
1150 | /// |
1151 | /// # Example: |
1152 | /// |
1153 | /// ```rust |
1154 | /// # use chrono::{DateTime, TimeZone, Utc}; |
1155 | /// # use serde_derive::Deserialize; |
1156 | /// use chrono::serde::ts_seconds_option::deserialize as from_tsopt; |
1157 | /// #[derive(Debug, PartialEq, Deserialize)] |
1158 | /// struct S { |
1159 | /// #[serde(deserialize_with = "from_tsopt" )] |
1160 | /// time: Option<DateTime<Utc>>, |
1161 | /// } |
1162 | /// |
1163 | /// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"# )?; |
1164 | /// assert_eq!(my_s, S { time: Utc.timestamp_opt(1431684000, 0).single() }); |
1165 | /// # Ok::<(), serde_json::Error>(()) |
1166 | /// ``` |
1167 | pub fn deserialize<'de, D>(d: D) -> Result<Option<DateTime<Utc>>, D::Error> |
1168 | where |
1169 | D: de::Deserializer<'de>, |
1170 | { |
1171 | d.deserialize_option(OptionSecondsTimestampVisitor) |
1172 | } |
1173 | |
1174 | struct OptionSecondsTimestampVisitor; |
1175 | |
1176 | impl<'de> de::Visitor<'de> for OptionSecondsTimestampVisitor { |
1177 | type Value = Option<DateTime<Utc>>; |
1178 | |
1179 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
1180 | formatter.write_str("a unix timestamp in seconds or none" ) |
1181 | } |
1182 | |
1183 | /// Deserialize a timestamp in seconds since the epoch |
1184 | fn visit_some<D>(self, d: D) -> Result<Self::Value, D::Error> |
1185 | where |
1186 | D: de::Deserializer<'de>, |
1187 | { |
1188 | d.deserialize_i64(SecondsTimestampVisitor).map(Some) |
1189 | } |
1190 | |
1191 | /// Deserialize a timestamp in seconds since the epoch |
1192 | fn visit_none<E>(self) -> Result<Self::Value, E> |
1193 | where |
1194 | E: de::Error, |
1195 | { |
1196 | Ok(None) |
1197 | } |
1198 | |
1199 | /// Deserialize a timestamp in seconds since the epoch |
1200 | fn visit_unit<E>(self) -> Result<Self::Value, E> |
1201 | where |
1202 | E: de::Error, |
1203 | { |
1204 | Ok(None) |
1205 | } |
1206 | } |
1207 | } |
1208 | |
1209 | #[cfg (test)] |
1210 | mod tests { |
1211 | #[cfg (feature = "clock" )] |
1212 | use crate::Local; |
1213 | use crate::{DateTime, FixedOffset, TimeZone, Utc}; |
1214 | use core::fmt; |
1215 | |
1216 | #[test ] |
1217 | fn test_serde_serialize() { |
1218 | assert_eq!( |
1219 | serde_json::to_string(&Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()).ok(), |
1220 | Some(r#""2014-07-24T12:34:06Z""# .to_owned()) |
1221 | ); |
1222 | assert_eq!( |
1223 | serde_json::to_string( |
1224 | &FixedOffset::east_opt(3660) |
1225 | .unwrap() |
1226 | .with_ymd_and_hms(2014, 7, 24, 12, 34, 6) |
1227 | .unwrap() |
1228 | ) |
1229 | .ok(), |
1230 | Some(r#""2014-07-24T12:34:06+01:01""# .to_owned()) |
1231 | ); |
1232 | assert_eq!( |
1233 | serde_json::to_string( |
1234 | &FixedOffset::east_opt(3650) |
1235 | .unwrap() |
1236 | .with_ymd_and_hms(2014, 7, 24, 12, 34, 6) |
1237 | .unwrap() |
1238 | ) |
1239 | .ok(), |
1240 | // An offset with seconds is not allowed by RFC 3339, so we round it to the nearest minute. |
1241 | // In this case `+01:00:50` becomes `+01:01` |
1242 | Some(r#""2014-07-24T12:34:06+01:01""# .to_owned()) |
1243 | ); |
1244 | } |
1245 | |
1246 | #[test ] |
1247 | fn test_serde_deserialize() { |
1248 | // should check against the offset as well (the normal DateTime comparison will ignore them) |
1249 | fn norm<Tz: TimeZone>(dt: &Option<DateTime<Tz>>) -> Option<(&DateTime<Tz>, &Tz::Offset)> { |
1250 | dt.as_ref().map(|dt| (dt, dt.offset())) |
1251 | } |
1252 | |
1253 | let dt: Option<DateTime<Utc>> = serde_json::from_str(r#""2014-07-24T12:34:06Z""# ).ok(); |
1254 | assert_eq!(norm(&dt), norm(&Some(Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()))); |
1255 | let dt: Option<DateTime<Utc>> = serde_json::from_str(r#""2014-07-24T13:57:06+01:23""# ).ok(); |
1256 | assert_eq!(norm(&dt), norm(&Some(Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()))); |
1257 | |
1258 | let dt: Option<DateTime<FixedOffset>> = |
1259 | serde_json::from_str(r#""2014-07-24T12:34:06Z""# ).ok(); |
1260 | assert_eq!( |
1261 | norm(&dt), |
1262 | norm(&Some( |
1263 | FixedOffset::east_opt(0).unwrap().with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap() |
1264 | )) |
1265 | ); |
1266 | let dt: Option<DateTime<FixedOffset>> = |
1267 | serde_json::from_str(r#""2014-07-24T13:57:06+01:23""# ).ok(); |
1268 | assert_eq!( |
1269 | norm(&dt), |
1270 | norm(&Some( |
1271 | FixedOffset::east_opt(60 * 60 + 23 * 60) |
1272 | .unwrap() |
1273 | .with_ymd_and_hms(2014, 7, 24, 13, 57, 6) |
1274 | .unwrap() |
1275 | )) |
1276 | ); |
1277 | |
1278 | // we don't know the exact local offset but we can check that |
1279 | // the conversion didn't change the instant itself |
1280 | #[cfg (feature = "clock" )] |
1281 | { |
1282 | let dt: DateTime<Local> = |
1283 | serde_json::from_str(r#""2014-07-24T12:34:06Z""# ).expect("local should parse" ); |
1284 | assert_eq!(dt, Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()); |
1285 | |
1286 | let dt: DateTime<Local> = serde_json::from_str(r#""2014-07-24T13:57:06+01:23""# ) |
1287 | .expect("local should parse with offset" ); |
1288 | assert_eq!(dt, Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()); |
1289 | } |
1290 | |
1291 | assert!(serde_json::from_str::<DateTime<Utc>>(r#""2014-07-32T12:34:06Z""# ).is_err()); |
1292 | assert!(serde_json::from_str::<DateTime<FixedOffset>>(r#""2014-07-32T12:34:06Z""# ).is_err()); |
1293 | } |
1294 | |
1295 | #[test ] |
1296 | fn test_serde_bincode() { |
1297 | // Bincode is relevant to test separately from JSON because |
1298 | // it is not self-describing. |
1299 | use bincode::{deserialize, serialize}; |
1300 | |
1301 | let dt = Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap(); |
1302 | let encoded = serialize(&dt).unwrap(); |
1303 | let decoded: DateTime<Utc> = deserialize(&encoded).unwrap(); |
1304 | assert_eq!(dt, decoded); |
1305 | assert_eq!(dt.offset(), decoded.offset()); |
1306 | } |
1307 | |
1308 | #[test ] |
1309 | fn test_serde_no_offset_debug() { |
1310 | use crate::{MappedLocalTime, NaiveDate, NaiveDateTime, Offset}; |
1311 | use core::fmt::Debug; |
1312 | |
1313 | #[derive (Clone)] |
1314 | struct TestTimeZone; |
1315 | impl Debug for TestTimeZone { |
1316 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
1317 | write!(f, "TEST" ) |
1318 | } |
1319 | } |
1320 | impl TimeZone for TestTimeZone { |
1321 | type Offset = TestTimeZone; |
1322 | fn from_offset(_state: &TestTimeZone) -> TestTimeZone { |
1323 | TestTimeZone |
1324 | } |
1325 | fn offset_from_local_date(&self, _local: &NaiveDate) -> MappedLocalTime<TestTimeZone> { |
1326 | MappedLocalTime::Single(TestTimeZone) |
1327 | } |
1328 | fn offset_from_local_datetime( |
1329 | &self, |
1330 | _local: &NaiveDateTime, |
1331 | ) -> MappedLocalTime<TestTimeZone> { |
1332 | MappedLocalTime::Single(TestTimeZone) |
1333 | } |
1334 | fn offset_from_utc_date(&self, _utc: &NaiveDate) -> TestTimeZone { |
1335 | TestTimeZone |
1336 | } |
1337 | fn offset_from_utc_datetime(&self, _utc: &NaiveDateTime) -> TestTimeZone { |
1338 | TestTimeZone |
1339 | } |
1340 | } |
1341 | impl Offset for TestTimeZone { |
1342 | fn fix(&self) -> FixedOffset { |
1343 | FixedOffset::east_opt(15 * 60 * 60).unwrap() |
1344 | } |
1345 | } |
1346 | |
1347 | let tz = TestTimeZone; |
1348 | assert_eq!(format!("{:?}" , &tz), "TEST" ); |
1349 | |
1350 | let dt = tz.with_ymd_and_hms(2023, 4, 24, 21, 10, 33).unwrap(); |
1351 | let encoded = serde_json::to_string(&dt).unwrap(); |
1352 | dbg!(&encoded); |
1353 | let decoded: DateTime<FixedOffset> = serde_json::from_str(&encoded).unwrap(); |
1354 | assert_eq!(dt, decoded); |
1355 | assert_eq!(dt.offset().fix(), *decoded.offset()); |
1356 | } |
1357 | } |
1358 | |