Coverage Report

Created: 2026-03-11 07:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/chrono-0.4.44/src/datetime/serde.rs
Line
Count
Source
1
use core::fmt;
2
use serde::{de, ser};
3
4
use super::DateTime;
5
use crate::format::{SecondsFormat, write_rfc3339};
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
0
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
34
0
    where
35
0
        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
0
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
43
0
                let naive = self.inner.naive_local();
44
0
                let offset = self.inner.offset.fix();
45
0
                write_rfc3339(f, naive, offset, SecondsFormat::AutoSi, true)
46
0
            }
47
        }
48
49
0
        serializer.collect_str(&FormatIso8601 { inner: self })
50
0
    }
51
}
52
53
struct DateTimeVisitor;
54
55
impl de::Visitor<'_> for DateTimeVisitor {
56
    type Value = DateTime<FixedOffset>;
57
58
0
    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
59
0
        formatter.write_str("an RFC 3339 formatted date and time string")
60
0
    }
61
62
0
    fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
63
0
    where
64
0
        E: de::Error,
65
    {
66
0
        value.parse().map_err(E::custom)
67
0
    }
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
0
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
78
0
    where
79
0
        D: de::Deserializer<'de>,
80
    {
81
0
        deserializer.deserialize_str(DateTimeVisitor)
82
0
    }
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
0
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
95
0
    where
96
0
        D: de::Deserializer<'de>,
97
    {
98
0
        deserializer.deserialize_str(DateTimeVisitor).map(|dt| dt.with_timezone(&Utc))
99
0
    }
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
0
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
114
0
    where
115
0
        D: de::Deserializer<'de>,
116
    {
117
0
        deserializer.deserialize_str(DateTimeVisitor).map(|dt| dt.with_timezone(&Local))
118
0
    }
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
0
    pub fn serialize<S>(dt: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error>
195
0
    where
196
0
        S: ser::Serializer,
197
    {
198
0
        serializer.serialize_i64(dt.timestamp_nanos_opt().ok_or(ser::Error::custom(
199
            "value out of range for a timestamp with nanosecond precision",
200
0
        ))?)
201
0
    }
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
0
    pub fn deserialize<'de, D>(d: D) -> Result<DateTime<Utc>, D::Error>
227
0
    where
228
0
        D: de::Deserializer<'de>,
229
    {
230
0
        d.deserialize_i64(NanoSecondsTimestampVisitor)
231
0
    }
232
233
    impl de::Visitor<'_> for NanoSecondsTimestampVisitor {
234
        type Value = DateTime<Utc>;
235
236
0
        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
237
0
            formatter.write_str("a unix timestamp in nanoseconds")
238
0
        }
239
240
        /// Deserialize a timestamp in nanoseconds since the epoch
241
0
        fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
242
0
        where
243
0
            E: de::Error,
244
        {
245
0
            Ok(DateTime::from_timestamp_nanos(value))
246
0
        }
247
248
        /// Deserialize a timestamp in nanoseconds since the epoch
249
0
        fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
250
0
        where
251
0
            E: de::Error,
252
        {
253
0
            DateTime::from_timestamp((value / 1_000_000_000) as i64, (value % 1_000_000_000) as u32)
254
0
                .ok_or_else(|| invalid_ts(value))
255
0
        }
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
/// ```
290
pub 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
0
    pub fn serialize<S>(opt: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error>
336
0
    where
337
0
        S: ser::Serializer,
338
    {
339
0
        match *opt {
340
0
            Some(ref dt) => serializer.serialize_some(&dt.timestamp_nanos_opt().ok_or(
341
0
                ser::Error::custom("value out of range for a timestamp with nanosecond precision"),
342
0
            )?),
343
0
            None => serializer.serialize_none(),
344
        }
345
0
    }
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
0
    pub fn deserialize<'de, D>(d: D) -> Result<Option<DateTime<Utc>>, D::Error>
368
0
    where
369
0
        D: de::Deserializer<'de>,
370
    {
371
0
        d.deserialize_option(OptionNanoSecondsTimestampVisitor)
372
0
    }
373
374
    struct OptionNanoSecondsTimestampVisitor;
375
376
    impl<'de> de::Visitor<'de> for OptionNanoSecondsTimestampVisitor {
377
        type Value = Option<DateTime<Utc>>;
378
379
0
        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
380
0
            formatter.write_str("a unix timestamp in nanoseconds or none")
381
0
        }
382
383
        /// Deserialize a timestamp in nanoseconds since the epoch
384
0
        fn visit_some<D>(self, d: D) -> Result<Self::Value, D::Error>
385
0
        where
386
0
            D: de::Deserializer<'de>,
387
        {
388
0
            d.deserialize_i64(NanoSecondsTimestampVisitor).map(Some)
389
0
        }
390
391
        /// Deserialize a timestamp in nanoseconds since the epoch
392
0
        fn visit_none<E>(self) -> Result<Self::Value, E>
393
0
        where
394
0
            E: de::Error,
395
        {
396
0
            Ok(None)
397
0
        }
398
399
        /// Deserialize a timestamp in nanoseconds since the epoch
400
0
        fn visit_unit<E>(self) -> Result<Self::Value, E>
401
0
        where
402
0
            E: de::Error,
403
        {
404
0
            Ok(None)
405
0
        }
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
/// ```
438
pub 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
0
    pub fn serialize<S>(dt: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error>
475
0
    where
476
0
        S: ser::Serializer,
477
    {
478
0
        serializer.serialize_i64(dt.timestamp_micros())
479
0
    }
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
0
    pub fn deserialize<'de, D>(d: D) -> Result<DateTime<Utc>, D::Error>
505
0
    where
506
0
        D: de::Deserializer<'de>,
507
    {
508
0
        d.deserialize_i64(MicroSecondsTimestampVisitor)
509
0
    }
510
511
    impl de::Visitor<'_> for MicroSecondsTimestampVisitor {
512
        type Value = DateTime<Utc>;
513
514
0
        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
515
0
            formatter.write_str("a unix timestamp in microseconds")
516
0
        }
517
518
        /// Deserialize a timestamp in milliseconds since the epoch
519
0
        fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
520
0
        where
521
0
            E: de::Error,
522
        {
523
0
            DateTime::from_timestamp_micros(value).ok_or_else(|| invalid_ts(value))
524
0
        }
525
526
        /// Deserialize a timestamp in milliseconds since the epoch
527
0
        fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
528
0
        where
529
0
            E: de::Error,
530
        {
531
0
            DateTime::from_timestamp(
532
0
                (value / 1_000_000) as i64,
533
0
                ((value % 1_000_000) * 1_000) as u32,
534
            )
535
0
            .ok_or_else(|| invalid_ts(value))
536
0
        }
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
/// ```
571
pub 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
0
    pub fn serialize<S>(opt: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error>
608
0
    where
609
0
        S: ser::Serializer,
610
    {
611
0
        match *opt {
612
0
            Some(ref dt) => serializer.serialize_some(&dt.timestamp_micros()),
613
0
            None => serializer.serialize_none(),
614
        }
615
0
    }
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
0
    pub fn deserialize<'de, D>(d: D) -> Result<Option<DateTime<Utc>>, D::Error>
638
0
    where
639
0
        D: de::Deserializer<'de>,
640
    {
641
0
        d.deserialize_option(OptionMicroSecondsTimestampVisitor)
642
0
    }
643
644
    struct OptionMicroSecondsTimestampVisitor;
645
646
    impl<'de> de::Visitor<'de> for OptionMicroSecondsTimestampVisitor {
647
        type Value = Option<DateTime<Utc>>;
648
649
0
        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
650
0
            formatter.write_str("a unix timestamp in microseconds or none")
651
0
        }
652
653
        /// Deserialize a timestamp in microseconds since the epoch
654
0
        fn visit_some<D>(self, d: D) -> Result<Self::Value, D::Error>
655
0
        where
656
0
            D: de::Deserializer<'de>,
657
        {
658
0
            d.deserialize_i64(MicroSecondsTimestampVisitor).map(Some)
659
0
        }
660
661
        /// Deserialize a timestamp in microseconds since the epoch
662
0
        fn visit_none<E>(self) -> Result<Self::Value, E>
663
0
        where
664
0
            E: de::Error,
665
        {
666
0
            Ok(None)
667
0
        }
668
669
        /// Deserialize a timestamp in microseconds since the epoch
670
0
        fn visit_unit<E>(self) -> Result<Self::Value, E>
671
0
        where
672
0
            E: de::Error,
673
        {
674
0
            Ok(None)
675
0
        }
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
/// ```
708
pub 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
0
    pub fn serialize<S>(dt: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error>
745
0
    where
746
0
        S: ser::Serializer,
747
    {
748
0
        serializer.serialize_i64(dt.timestamp_millis())
749
0
    }
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
0
    pub fn deserialize<'de, D>(d: D) -> Result<DateTime<Utc>, D::Error>
775
0
    where
776
0
        D: de::Deserializer<'de>,
777
    {
778
0
        d.deserialize_i64(MilliSecondsTimestampVisitor).map(|dt| dt.with_timezone(&Utc))
779
0
    }
780
781
    impl de::Visitor<'_> for MilliSecondsTimestampVisitor {
782
        type Value = DateTime<Utc>;
783
784
0
        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
785
0
            formatter.write_str("a unix timestamp in milliseconds")
786
0
        }
787
788
        /// Deserialize a timestamp in milliseconds since the epoch
789
0
        fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
790
0
        where
791
0
            E: de::Error,
792
        {
793
0
            DateTime::from_timestamp_millis(value).ok_or_else(|| invalid_ts(value))
794
0
        }
795
796
        /// Deserialize a timestamp in milliseconds since the epoch
797
0
        fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
798
0
        where
799
0
            E: de::Error,
800
        {
801
0
            DateTime::from_timestamp((value / 1000) as i64, ((value % 1000) * 1_000_000) as u32)
802
0
                .ok_or_else(|| invalid_ts(value))
803
0
        }
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
/// ```
838
pub 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
0
    pub fn serialize<S>(opt: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error>
875
0
    where
876
0
        S: ser::Serializer,
877
    {
878
0
        match *opt {
879
0
            Some(ref dt) => serializer.serialize_some(&dt.timestamp_millis()),
880
0
            None => serializer.serialize_none(),
881
        }
882
0
    }
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
0
    pub fn deserialize<'de, D>(d: D) -> Result<Option<DateTime<Utc>>, D::Error>
916
0
    where
917
0
        D: de::Deserializer<'de>,
918
    {
919
0
        d.deserialize_option(OptionMilliSecondsTimestampVisitor)
920
0
            .map(|opt| opt.map(|dt| dt.with_timezone(&Utc)))
921
0
    }
922
923
    struct OptionMilliSecondsTimestampVisitor;
924
925
    impl<'de> de::Visitor<'de> for OptionMilliSecondsTimestampVisitor {
926
        type Value = Option<DateTime<Utc>>;
927
928
0
        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
929
0
            formatter.write_str("a unix timestamp in milliseconds or none")
930
0
        }
931
932
        /// Deserialize a timestamp in milliseconds since the epoch
933
0
        fn visit_some<D>(self, d: D) -> Result<Self::Value, D::Error>
934
0
        where
935
0
            D: de::Deserializer<'de>,
936
        {
937
0
            d.deserialize_i64(MilliSecondsTimestampVisitor).map(Some)
938
0
        }
939
940
        /// Deserialize a timestamp in milliseconds since the epoch
941
0
        fn visit_none<E>(self) -> Result<Self::Value, E>
942
0
        where
943
0
            E: de::Error,
944
        {
945
0
            Ok(None)
946
0
        }
947
948
        /// Deserialize a timestamp in milliseconds since the epoch
949
0
        fn visit_unit<E>(self) -> Result<Self::Value, E>
950
0
        where
951
0
            E: de::Error,
952
        {
953
0
            Ok(None)
954
0
        }
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
/// ```
983
pub 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
0
    pub fn serialize<S>(dt: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error>
1014
0
    where
1015
0
        S: ser::Serializer,
1016
    {
1017
0
        serializer.serialize_i64(dt.timestamp())
1018
0
    }
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
0
    pub fn deserialize<'de, D>(d: D) -> Result<DateTime<Utc>, D::Error>
1041
0
    where
1042
0
        D: de::Deserializer<'de>,
1043
    {
1044
0
        d.deserialize_i64(SecondsTimestampVisitor)
1045
0
    }
1046
1047
    impl de::Visitor<'_> for SecondsTimestampVisitor {
1048
        type Value = DateTime<Utc>;
1049
1050
0
        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1051
0
            formatter.write_str("a unix timestamp in seconds")
1052
0
        }
1053
1054
        /// Deserialize a timestamp in seconds since the epoch
1055
0
        fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
1056
0
        where
1057
0
            E: de::Error,
1058
        {
1059
0
            DateTime::from_timestamp_secs(value).ok_or_else(|| invalid_ts(value))
1060
0
        }
1061
1062
        /// Deserialize a timestamp in seconds since the epoch
1063
0
        fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
1064
0
        where
1065
0
            E: de::Error,
1066
        {
1067
0
            if value > i64::MAX as u64 {
1068
0
                Err(invalid_ts(value))
1069
            } else {
1070
0
                DateTime::from_timestamp_secs(value as i64).ok_or_else(|| invalid_ts(value))
1071
            }
1072
0
        }
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
/// ```
1101
pub 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
0
    pub fn serialize<S>(opt: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error>
1130
0
    where
1131
0
        S: ser::Serializer,
1132
    {
1133
0
        match *opt {
1134
0
            Some(ref dt) => serializer.serialize_some(&dt.timestamp()),
1135
0
            None => serializer.serialize_none(),
1136
        }
1137
0
    }
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
0
    pub fn deserialize<'de, D>(d: D) -> Result<Option<DateTime<Utc>>, D::Error>
1160
0
    where
1161
0
        D: de::Deserializer<'de>,
1162
    {
1163
0
        d.deserialize_option(OptionSecondsTimestampVisitor)
1164
0
    }
1165
1166
    struct OptionSecondsTimestampVisitor;
1167
1168
    impl<'de> de::Visitor<'de> for OptionSecondsTimestampVisitor {
1169
        type Value = Option<DateTime<Utc>>;
1170
1171
0
        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1172
0
            formatter.write_str("a unix timestamp in seconds or none")
1173
0
        }
1174
1175
        /// Deserialize a timestamp in seconds since the epoch
1176
0
        fn visit_some<D>(self, d: D) -> Result<Self::Value, D::Error>
1177
0
        where
1178
0
            D: de::Deserializer<'de>,
1179
        {
1180
0
            d.deserialize_i64(SecondsTimestampVisitor).map(Some)
1181
0
        }
1182
1183
        /// Deserialize a timestamp in seconds since the epoch
1184
0
        fn visit_none<E>(self) -> Result<Self::Value, E>
1185
0
        where
1186
0
            E: de::Error,
1187
        {
1188
0
            Ok(None)
1189
0
        }
1190
1191
        /// Deserialize a timestamp in seconds since the epoch
1192
0
        fn visit_unit<E>(self) -> Result<Self::Value, E>
1193
0
        where
1194
0
            E: de::Error,
1195
        {
1196
0
            Ok(None)
1197
0
        }
1198
    }
1199
}
1200
1201
#[cfg(test)]
1202
mod 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
}