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