chrono/datetime/serde.rs
1use core::fmt;
2use serde::{de, ser};
3
4use super::DateTime;
5use crate::format::{SecondsFormat, write_rfc3339};
6#[cfg(feature = "clock")]
7use crate::offset::Local;
8use crate::offset::{FixedOffset, Offset, TimeZone, Utc};
9
10#[doc(hidden)]
11#[derive(Debug)]
12pub struct SecondsTimestampVisitor;
13
14#[doc(hidden)]
15#[derive(Debug)]
16pub struct NanoSecondsTimestampVisitor;
17
18#[doc(hidden)]
19#[derive(Debug)]
20pub struct MicroSecondsTimestampVisitor;
21
22#[doc(hidden)]
23#[derive(Debug)]
24pub 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.
32impl<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 = self.inner.naive_local();
44 let offset = self.inner.offset.fix();
45 write_rfc3339(f, naive, offset, SecondsFormat::AutoSi, true)
46 }
47 }
48
49 serializer.collect_str(&FormatIso8601 { inner: self })
50 }
51}
52
53struct DateTimeVisitor;
54
55impl de::Visitor<'_> for DateTimeVisitor {
56 type Value = DateTime<FixedOffset>;
57
58 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
59 formatter.write_str("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.
76impl<'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(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.
93impl<'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| 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")]
112impl<'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| 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/// ```
150pub 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/// ```
294pub 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/// ```
442pub 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/// ```
579pub 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/// ```
716pub 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/// ```
846pub 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/// ```
991pub 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/// ```
1109pub 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)]
1210mod 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!(
1293 serde_json::from_str::<DateTime<FixedOffset>>(r#""2014-07-32T12:34:06Z""#).is_err()
1294 );
1295 }
1296
1297 #[test]
1298 fn test_serde_bincode() {
1299 // Bincode is relevant to test separately from JSON because
1300 // it is not self-describing.
1301 use bincode::{deserialize, serialize};
1302
1303 let dt = Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap();
1304 let encoded = serialize(&dt).unwrap();
1305 let decoded: DateTime<Utc> = deserialize(&encoded).unwrap();
1306 assert_eq!(dt, decoded);
1307 assert_eq!(dt.offset(), decoded.offset());
1308 }
1309
1310 #[test]
1311 fn test_serde_no_offset_debug() {
1312 use crate::{MappedLocalTime, NaiveDate, NaiveDateTime, Offset};
1313 use core::fmt::Debug;
1314
1315 #[derive(Clone)]
1316 struct TestTimeZone;
1317 impl Debug for TestTimeZone {
1318 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1319 write!(f, "TEST")
1320 }
1321 }
1322 impl TimeZone for TestTimeZone {
1323 type Offset = TestTimeZone;
1324 fn from_offset(_state: &TestTimeZone) -> TestTimeZone {
1325 TestTimeZone
1326 }
1327 fn offset_from_local_date(&self, _local: &NaiveDate) -> MappedLocalTime<TestTimeZone> {
1328 MappedLocalTime::Single(TestTimeZone)
1329 }
1330 fn offset_from_local_datetime(
1331 &self,
1332 _local: &NaiveDateTime,
1333 ) -> MappedLocalTime<TestTimeZone> {
1334 MappedLocalTime::Single(TestTimeZone)
1335 }
1336 fn offset_from_utc_date(&self, _utc: &NaiveDate) -> TestTimeZone {
1337 TestTimeZone
1338 }
1339 fn offset_from_utc_datetime(&self, _utc: &NaiveDateTime) -> TestTimeZone {
1340 TestTimeZone
1341 }
1342 }
1343 impl Offset for TestTimeZone {
1344 fn fix(&self) -> FixedOffset {
1345 FixedOffset::east_opt(15 * 60 * 60).unwrap()
1346 }
1347 }
1348
1349 let tz = TestTimeZone;
1350 assert_eq!(format!("{:?}", &tz), "TEST");
1351
1352 let dt = tz.with_ymd_and_hms(2023, 4, 24, 21, 10, 33).unwrap();
1353 let encoded = serde_json::to_string(&dt).unwrap();
1354 dbg!(&encoded);
1355 let decoded: DateTime<FixedOffset> = serde_json::from_str(&encoded).unwrap();
1356 assert_eq!(dt, decoded);
1357 assert_eq!(dt.offset().fix(), *decoded.offset());
1358 }
1359}