jiff/fmt/
serde.rs

1/*!
2This module provides helpers to use with [Serde].
3
4Some helpers, like those for `Timestamp`, are exposed as modules meant
5to be used with Serde's [`with` attribute]. Others, like for `Span` and
6`SignedDuration`, only provide serialization helpers to be used with Serde's
7[`serialize_with` attribute].
8
9# Module hierarchy
10
11The available helpers can be more quickly understood by looking at a fully
12rendered tree of this module's hierarchy. Only the leaves of the tree are
13usable with Serde's attributes. For each leaf, the full path is spelled out for
14easy copy & paste.
15
16* [`duration`]
17    * [`friendly`](self::duration::friendly)
18        * [`compact`](self::duration::friendly::compact)
19            * [`jiff::fmt::serde::duration::friendly::compact::required`](self::duration::friendly::compact::required)
20            * [`jiff::fmt::serde::duration::friendly::compact::optional`](self::duration::friendly::compact::optional)
21* [`span`]
22    * [`friendly`](self::span::friendly)
23        * [`compact`](self::span::friendly::compact)
24            * [`jiff::fmt::serde::span::friendly::compact::required`](self::span::friendly::compact::required)
25            * [`jiff::fmt::serde::span::friendly::compact::optional`](self::span::friendly::compact::optional)
26* [`timestamp`]
27    * [`second`](self::timestamp::second)
28        * [`jiff::fmt::serde::timestamp::second::required`](self::timestamp::second::required)
29        * [`jiff::fmt::serde::timestamp::second::optional`](self::timestamp::second::optional)
30    * [`millisecond`](self::timestamp::millisecond)
31        * [`jiff::fmt::serde::timestamp::millisecond::required`](self::timestamp::millisecond::required)
32        * [`jiff::fmt::serde::timestamp::millisecond::optional`](self::timestamp::millisecond::optional)
33    * [`microsecond`](self::timestamp::millisecond)
34        * [`jiff::fmt::serde::timestamp::microsecond::required`](self::timestamp::microsecond::required)
35        * [`jiff::fmt::serde::timestamp::microsecond::optional`](self::timestamp::microsecond::optional)
36    * [`nanosecond`](self::timestamp::millisecond)
37        * [`jiff::fmt::serde::timestamp::nanosecond::required`](self::timestamp::nanosecond::required)
38        * [`jiff::fmt::serde::timestamp::nanosecond::optional`](self::timestamp::nanosecond::optional)
39* [`tz`]
40    * [`jiff::fmt::serde::tz::required`](self::tz::required)
41    * [`jiff::fmt::serde::tz::optional`](self::tz::optional)
42
43# Example: timestamps as an integer
44
45This example shows how to deserialize an integer number of seconds since the
46Unix epoch into a [`Timestamp`](crate::Timestamp). And the reverse operation
47for serialization:
48
49```
50use jiff::Timestamp;
51
52#[derive(Debug, serde::Deserialize, serde::Serialize)]
53struct Record {
54    #[serde(with = "jiff::fmt::serde::timestamp::second::required")]
55    timestamp: Timestamp,
56}
57
58let json = r#"{"timestamp":1517644800}"#;
59let got: Record = serde_json::from_str(&json)?;
60assert_eq!(got.timestamp, Timestamp::from_second(1517644800)?);
61assert_eq!(serde_json::to_string(&got)?, json);
62
63# Ok::<(), Box<dyn std::error::Error>>(())
64```
65
66# Example: optional timestamp support
67
68And this example shows how to use an `Option<Timestamp>` instead of a
69`Timestamp`. Note that in this case, we show how to roundtrip the number of
70**milliseconds** since the Unix epoch:
71
72```
73use jiff::Timestamp;
74
75#[derive(Debug, serde::Deserialize, serde::Serialize)]
76struct Record {
77    #[serde(with = "jiff::fmt::serde::timestamp::millisecond::optional")]
78    timestamp: Option<Timestamp>,
79}
80
81let json = r#"{"timestamp":1517644800123}"#;
82let got: Record = serde_json::from_str(&json)?;
83assert_eq!(got.timestamp, Some(Timestamp::from_millisecond(1517644800_123)?));
84assert_eq!(serde_json::to_string(&got)?, json);
85
86# Ok::<(), Box<dyn std::error::Error>>(())
87```
88
89# Example: the "friendly" duration format
90
91The [`Span`](crate::Span) and [`SignedDuration`](crate::SignedDuration) types
92in this crate both implement Serde's `Serialize` and `Deserialize` traits. For
93`Serialize`, they both use the [ISO 8601 Temporal duration format], but for
94`Deserialize`, they both support the ISO 8601 Temporal duration format and
95the ["friendly" duration format] simultaneously. In order to serialize either
96type in the "friendly" format, you can either define your own serialization
97functions or use one of the convenience routines provided by this module. For
98example:
99
100```
101use jiff::{ToSpan, Span};
102
103#[derive(Debug, serde::Deserialize, serde::Serialize)]
104struct Record {
105    #[serde(
106        serialize_with = "jiff::fmt::serde::span::friendly::compact::required"
107    )]
108    span: Span,
109}
110
111let json = r#"{"span":"1 year 2 months 36 hours 1100ms"}"#;
112let got: Record = serde_json::from_str(&json)?;
113assert_eq!(
114    got.span,
115    1.year().months(2).hours(36).milliseconds(1100).fieldwise(),
116);
117
118let expected = r#"{"span":"1y 2mo 36h 1100ms"}"#;
119assert_eq!(serde_json::to_string(&got).unwrap(), expected);
120
121# Ok::<(), Box<dyn std::error::Error>>(())
122```
123
124[Serde]: https://serde.rs/
125[`with` attribute]: https://serde.rs/field-attrs.html#with
126[`serialize_with` attribute]: https://serde.rs/field-attrs.html#serialize_with
127[ISO 8601 Temporal duration format]: crate::fmt::temporal
128["friendly" duration format]: crate::fmt::friendly
129*/
130
131/// Convenience routines for serializing [`SignedDuration`](crate::SignedDuration)
132/// values.
133///
134/// These convenience routines exist because the `Serialize` implementation for
135/// `SignedDuration` always uses the ISO 8601 duration format. These routines
136/// provide a way to use the "[friendly](crate::fmt::friendly)" format.
137///
138/// Only serialization routines are provided because a `SignedDuration`'s
139/// `Deserialize` implementation automatically handles both the ISO 8601
140/// duration format and the "friendly" format.
141///
142/// # Advice
143///
144/// The `Serialize` implementation uses ISO 8601 because it is a widely
145/// accepted interchange format for communicating durations. If you need to
146/// inter-operate with other systems, it is almost certainly the correct
147/// choice.
148///
149/// The "friendly" format does not adhere to any universal specified format.
150/// However, it is perhaps easier to read. Beyond that, its utility for
151/// `SignedDuration` is somewhat less compared to [`Span`](crate::Span), since
152/// for `Span`, the friendly format preserves all components of the `Span`
153/// faithfully. But a `SignedDuration` is just a 96-bit integer of nanoseconds,
154/// so there are no individual components to preserve. Still, even with a
155/// `SignedDuration`, you might prefer the friendly format.
156///
157/// # Available routines
158///
159/// A [`SpanPrinter`](crate::fmt::friendly::SpanPrinter) has a lot of different
160/// configuration options. The convenience routines provided by this module
161/// only cover a small space of those options since it isn't feasible to
162/// provide a convenience routine for every possible set of configuration
163/// options.
164///
165/// While more convenience routines could be added (please file an issue), only
166/// the most common or popular such routines can be feasibly added. So in the
167/// case where a convenience routine isn't available for the configuration you
168/// want, you can very easily define your own `serialize_with` routine.
169///
170/// The recommended approach is to define a function and a type that
171/// implements the `std::fmt::Display` trait. This way, if a serializer can
172/// efficiently support `Display` implementations, then an allocation can be
173/// avoided.
174///
175/// ```
176/// use jiff::SignedDuration;
177///
178/// #[derive(Debug, serde::Deserialize, serde::Serialize)]
179/// struct Data {
180///     #[serde(serialize_with = "custom_friendly")]
181///     duration: SignedDuration,
182/// }
183///
184/// let json = r#"{"duration": "36 hours 1100ms"}"#;
185/// let got: Data = serde_json::from_str(&json).unwrap();
186/// assert_eq!(got.duration, SignedDuration::new(36 * 60 * 60 + 1, 100_000_000));
187///
188/// let expected = r#"{"duration":"36:00:01.100"}"#;
189/// assert_eq!(serde_json::to_string(&got).unwrap(), expected);
190///
191/// fn custom_friendly<S: serde::Serializer>(
192///     duration: &SignedDuration,
193///     se: S,
194/// ) -> Result<S::Ok, S::Error> {
195///     struct Custom<'a>(&'a SignedDuration);
196///
197///     impl<'a> std::fmt::Display for Custom<'a> {
198///         fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
199///             use jiff::fmt::{friendly::SpanPrinter, StdFmtWrite};
200///
201///             static PRINTER: SpanPrinter = SpanPrinter::new()
202///                 .hours_minutes_seconds(true)
203///                 .precision(Some(3));
204///
205///             PRINTER
206///                 .print_duration(self.0, StdFmtWrite(f))
207///                 .map_err(|_| core::fmt::Error)
208///         }
209///     }
210///
211///     se.collect_str(&Custom(duration))
212/// }
213/// ```
214///
215/// Recall from above that you only need a custom serialization routine
216/// for this. Namely, deserialization automatically supports parsing all
217/// configuration options for serialization unconditionally.
218pub mod duration {
219    /// Serialize a `Span` in the [`friendly`](crate::fmt::friendly) duration
220    /// format.
221    pub mod friendly {
222        /// Serialize a `SignedDuration` in the
223        /// [`friendly`](crate::fmt::friendly) duration format using compact
224        /// designators.
225        pub mod compact {
226            use crate::fmt::{friendly, StdFmtWrite};
227
228            struct CompactDuration<'a>(&'a crate::SignedDuration);
229
230            impl<'a> core::fmt::Display for CompactDuration<'a> {
231                fn fmt(
232                    &self,
233                    f: &mut core::fmt::Formatter,
234                ) -> core::fmt::Result {
235                    static PRINTER: friendly::SpanPrinter =
236                        friendly::SpanPrinter::new()
237                            .designator(friendly::Designator::Compact);
238                    PRINTER
239                        .print_duration(self.0, StdFmtWrite(f))
240                        .map_err(|_| core::fmt::Error)
241                }
242            }
243
244            /// Serialize a required `SignedDuration` in the [`friendly`]
245            /// duration format using compact designators.
246            #[inline]
247            pub fn required<S: serde::Serializer>(
248                duration: &crate::SignedDuration,
249                se: S,
250            ) -> Result<S::Ok, S::Error> {
251                se.collect_str(&CompactDuration(duration))
252            }
253
254            /// Serialize an optional `SignedDuration` in the [`friendly`]
255            /// duration format using compact designators.
256            #[inline]
257            pub fn optional<S: serde::Serializer>(
258                duration: &Option<crate::SignedDuration>,
259                se: S,
260            ) -> Result<S::Ok, S::Error> {
261                match *duration {
262                    None => se.serialize_none(),
263                    Some(ref duration) => required(duration, se),
264                }
265            }
266        }
267    }
268}
269
270/// Convenience routines for serializing [`Span`](crate::Span) values.
271///
272/// These convenience routines exist because the `Serialize` implementation for
273/// `Span` always uses the ISO 8601 duration format. These routines provide a
274/// way to use the "[friendly](crate::fmt::friendly)" format.
275///
276/// Only serialization routines are provided because a `Span`'s `Deserialize`
277/// implementation automatically handles both the ISO 8601 duration format and
278/// the "friendly" format.
279///
280/// # Advice
281///
282/// The `Serialize` implementation uses ISO 8601 because it is a widely
283/// accepted interchange format for communicating durations. If you need to
284/// inter-operate with other systems, it is almost certainly the correct choice.
285///
286/// The "friendly" format does not adhere to any universal specified format.
287/// However, it is perhaps easier to read, and crucially, unambiguously
288/// represents all components of a `Span` faithfully. (In contrast, the ISO
289/// 8601 format always normalizes sub-second durations into fractional seconds,
290/// which means durations like `1100ms` and `1s100ms` are alwasys considered
291/// equivalent.)
292///
293/// # Available routines
294///
295/// A [`SpanPrinter`](crate::fmt::friendly::SpanPrinter) has a lot of different
296/// configuration options. The convenience routines provided by this module
297/// only cover a small space of those options since it isn't feasible to
298/// provide a convenience routine for every possible set of configuration
299/// options.
300///
301/// While more convenience routines could be added (please file an issue), only
302/// the most common or popular such routines can be feasibly added. So in the
303/// case where a convenience routine isn't available for the configuration you
304/// want, you can very easily define your own `serialize_with` routine.
305///
306/// The recommended approach is to define a function and a type that
307/// implements the `std::fmt::Display` trait. This way, if a serializer can
308/// efficiently support `Display` implementations, then an allocation can be
309/// avoided.
310///
311/// ```
312/// use jiff::{Span, ToSpan};
313///
314/// #[derive(Debug, serde::Deserialize, serde::Serialize)]
315/// struct Data {
316///     #[serde(serialize_with = "custom_friendly")]
317///     duration: Span,
318/// }
319///
320/// let json = r#"{"duration": "1 year 2 months 36 hours 1100ms"}"#;
321/// let got: Data = serde_json::from_str(&json).unwrap();
322/// assert_eq!(
323///     got.duration,
324///     1.year().months(2).hours(36).milliseconds(1100).fieldwise(),
325/// );
326///
327/// let expected = r#"{"duration":"1 year, 2 months, 36:00:01.100"}"#;
328/// assert_eq!(serde_json::to_string(&got).unwrap(), expected);
329///
330/// fn custom_friendly<S: serde::Serializer>(
331///     span: &Span,
332///     se: S,
333/// ) -> Result<S::Ok, S::Error> {
334///     struct Custom<'a>(&'a Span);
335///
336///     impl<'a> std::fmt::Display for Custom<'a> {
337///         fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
338///             use jiff::fmt::{
339///                 friendly::{Designator, Spacing, SpanPrinter},
340///                 StdFmtWrite,
341///             };
342///
343///             static PRINTER: SpanPrinter = SpanPrinter::new()
344///                 .designator(Designator::Verbose)
345///                 .comma_after_designator(true)
346///                 .spacing(Spacing::BetweenUnitsAndDesignators)
347///                 .hours_minutes_seconds(true)
348///                 .precision(Some(3));
349///
350///             PRINTER
351///                 .print_span(self.0, StdFmtWrite(f))
352///                 .map_err(|_| core::fmt::Error)
353///         }
354///     }
355///
356///     se.collect_str(&Custom(span))
357/// }
358/// ```
359///
360/// Recall from above that you only need a custom serialization routine
361/// for this. Namely, deserialization automatically supports parsing all
362/// configuration options for serialization unconditionally.
363pub mod span {
364    /// Serialize a `Span` in the [`friendly`](crate::fmt::friendly) duration
365    /// format.
366    pub mod friendly {
367        /// Serialize a `Span` in the [`friendly`](crate::fmt::friendly)
368        /// duration format using compact designators.
369        pub mod compact {
370            use crate::fmt::{friendly, StdFmtWrite};
371
372            struct CompactSpan<'a>(&'a crate::Span);
373
374            impl<'a> core::fmt::Display for CompactSpan<'a> {
375                fn fmt(
376                    &self,
377                    f: &mut core::fmt::Formatter,
378                ) -> core::fmt::Result {
379                    static PRINTER: friendly::SpanPrinter =
380                        friendly::SpanPrinter::new()
381                            .designator(friendly::Designator::Compact);
382                    PRINTER
383                        .print_span(self.0, StdFmtWrite(f))
384                        .map_err(|_| core::fmt::Error)
385                }
386            }
387
388            /// Serialize a required `Span` in the [`friendly`] duration format
389            /// using compact designators.
390            #[inline]
391            pub fn required<S: serde::Serializer>(
392                span: &crate::Span,
393                se: S,
394            ) -> Result<S::Ok, S::Error> {
395                se.collect_str(&CompactSpan(span))
396            }
397
398            /// Serialize an optional `Span` in the [`friendly`] duration
399            /// format using compact designators.
400            #[inline]
401            pub fn optional<S: serde::Serializer>(
402                span: &Option<crate::Span>,
403                se: S,
404            ) -> Result<S::Ok, S::Error> {
405                match *span {
406                    None => se.serialize_none(),
407                    Some(ref span) => required(span, se),
408                }
409            }
410        }
411    }
412}
413
414/// Convenience routines for (de)serializing [`Timestamp`](crate::Timestamp) as
415/// raw integer values.
416///
417/// At present, the helpers are limited to serializing and deserializing
418/// [`Timestamp`](crate::Timestamp) values as an integer number of seconds,
419/// milliseconds, microseconds or nanoseconds.
420///
421/// # Advice
422///
423/// In general, these helpers should only be used to interface with "legacy"
424/// APIs that transmit times as integer number of seconds (or milliseconds or
425/// whatever). If you're designing a new API and need to transmit instants in
426/// time that don't care about time zones, then you should use `Timestamp`
427/// directly. It will automatically use RFC 3339. (And if you do want to
428/// include the time zone, then using [`Zoned`](crate::Zoned) directly will
429/// work as well by utilizing the RFC 9557 extension to RFC 3339.)
430pub mod timestamp {
431    use serde::de;
432
433    /// A generic visitor for `Option<Timestamp>`.
434    struct OptionalVisitor<V>(V);
435
436    impl<'de, V: de::Visitor<'de, Value = crate::Timestamp>> de::Visitor<'de>
437        for OptionalVisitor<V>
438    {
439        type Value = Option<crate::Timestamp>;
440
441        fn expecting(
442            &self,
443            f: &mut core::fmt::Formatter,
444        ) -> core::fmt::Result {
445            f.write_str(
446                "an integer number of seconds from the Unix epoch or `None`",
447            )
448        }
449
450        #[inline]
451        fn visit_some<D: de::Deserializer<'de>>(
452            self,
453            de: D,
454        ) -> Result<Option<crate::Timestamp>, D::Error> {
455            de.deserialize_i64(self.0).map(Some)
456        }
457
458        #[inline]
459        fn visit_none<E: de::Error>(
460            self,
461        ) -> Result<Option<crate::Timestamp>, E> {
462            Ok(None)
463        }
464    }
465
466    /// (De)serialize an integer number of seconds from the Unix epoch.
467    pub mod second {
468        use serde::de;
469
470        struct Visitor;
471
472        impl<'de> de::Visitor<'de> for Visitor {
473            type Value = crate::Timestamp;
474
475            fn expecting(
476                &self,
477                f: &mut core::fmt::Formatter,
478            ) -> core::fmt::Result {
479                f.write_str("an integer number of seconds from the Unix epoch")
480            }
481
482            #[inline]
483            fn visit_i8<E: de::Error>(
484                self,
485                v: i8,
486            ) -> Result<crate::Timestamp, E> {
487                self.visit_i64(i64::from(v))
488            }
489
490            #[inline]
491            fn visit_u8<E: de::Error>(
492                self,
493                v: u8,
494            ) -> Result<crate::Timestamp, E> {
495                self.visit_i64(i64::from(v))
496            }
497
498            #[inline]
499            fn visit_i16<E: de::Error>(
500                self,
501                v: i16,
502            ) -> Result<crate::Timestamp, E> {
503                self.visit_i64(i64::from(v))
504            }
505
506            #[inline]
507            fn visit_u16<E: de::Error>(
508                self,
509                v: u16,
510            ) -> Result<crate::Timestamp, E> {
511                self.visit_i64(i64::from(v))
512            }
513
514            #[inline]
515            fn visit_i32<E: de::Error>(
516                self,
517                v: i32,
518            ) -> Result<crate::Timestamp, E> {
519                self.visit_i64(i64::from(v))
520            }
521
522            #[inline]
523            fn visit_u32<E: de::Error>(
524                self,
525                v: u32,
526            ) -> Result<crate::Timestamp, E> {
527                self.visit_i64(i64::from(v))
528            }
529
530            #[inline]
531            fn visit_i64<E: de::Error>(
532                self,
533                v: i64,
534            ) -> Result<crate::Timestamp, E> {
535                crate::Timestamp::from_second(v).map_err(de::Error::custom)
536            }
537
538            #[inline]
539            fn visit_u64<E: de::Error>(
540                self,
541                v: u64,
542            ) -> Result<crate::Timestamp, E> {
543                let v = i64::try_from(v).map_err(|_| {
544                    de::Error::custom(format_args!(
545                        "got unsigned integer {v} seconds, \
546                         which is too big to fit in a Jiff `Timestamp`",
547                    ))
548                })?;
549                self.visit_i64(v)
550            }
551
552            #[inline]
553            fn visit_i128<E: de::Error>(
554                self,
555                v: i128,
556            ) -> Result<crate::Timestamp, E> {
557                let v = i64::try_from(v).map_err(|_| {
558                    de::Error::custom(format_args!(
559                        "got signed integer {v} seconds, \
560                         which is too big to fit in a Jiff `Timestamp`",
561                    ))
562                })?;
563                self.visit_i64(v)
564            }
565
566            #[inline]
567            fn visit_u128<E: de::Error>(
568                self,
569                v: u128,
570            ) -> Result<crate::Timestamp, E> {
571                let v = i64::try_from(v).map_err(|_| {
572                    de::Error::custom(format_args!(
573                        "got unsigned integer {v} seconds, \
574                         which is too big to fit in a Jiff `Timestamp`",
575                    ))
576                })?;
577                self.visit_i64(v)
578            }
579        }
580
581        /// (De)serialize a required integer number of seconds from the Unix
582        /// epoch.
583        pub mod required {
584            /// Serialize a required integer number of seconds since the Unix
585            /// epoch.
586            #[inline]
587            pub fn serialize<S: serde::Serializer>(
588                timestamp: &crate::Timestamp,
589                se: S,
590            ) -> Result<S::Ok, S::Error> {
591                se.serialize_i64(timestamp.as_second())
592            }
593
594            /// Deserialize a required integer number of seconds since the
595            /// Unix epoch.
596            #[inline]
597            pub fn deserialize<'de, D: serde::Deserializer<'de>>(
598                de: D,
599            ) -> Result<crate::Timestamp, D::Error> {
600                de.deserialize_i64(super::Visitor)
601            }
602        }
603
604        /// (De)serialize an optional integer number of seconds from the Unix
605        /// epoch.
606        pub mod optional {
607            /// Serialize an optional integer number of seconds since the Unix
608            /// epoch.
609            #[inline]
610            pub fn serialize<S: serde::Serializer>(
611                timestamp: &Option<crate::Timestamp>,
612                se: S,
613            ) -> Result<S::Ok, S::Error> {
614                match *timestamp {
615                    None => se.serialize_none(),
616                    Some(ts) => se.serialize_i64(ts.as_second()),
617                }
618            }
619
620            /// Deserialize an optional integer number of seconds since the
621            /// Unix epoch.
622            #[inline]
623            pub fn deserialize<'de, D: serde::Deserializer<'de>>(
624                de: D,
625            ) -> Result<Option<crate::Timestamp>, D::Error> {
626                de.deserialize_option(super::super::OptionalVisitor(
627                    super::Visitor,
628                ))
629            }
630        }
631    }
632
633    /// (De)serialize an integer number of milliseconds from the Unix epoch.
634    pub mod millisecond {
635        use serde::de;
636
637        struct Visitor;
638
639        impl<'de> de::Visitor<'de> for Visitor {
640            type Value = crate::Timestamp;
641
642            fn expecting(
643                &self,
644                f: &mut core::fmt::Formatter,
645            ) -> core::fmt::Result {
646                f.write_str(
647                    "an integer number of milliseconds from the Unix epoch",
648                )
649            }
650
651            #[inline]
652            fn visit_i8<E: de::Error>(
653                self,
654                v: i8,
655            ) -> Result<crate::Timestamp, E> {
656                self.visit_i64(i64::from(v))
657            }
658
659            #[inline]
660            fn visit_u8<E: de::Error>(
661                self,
662                v: u8,
663            ) -> Result<crate::Timestamp, E> {
664                self.visit_i64(i64::from(v))
665            }
666
667            #[inline]
668            fn visit_i16<E: de::Error>(
669                self,
670                v: i16,
671            ) -> Result<crate::Timestamp, E> {
672                self.visit_i64(i64::from(v))
673            }
674
675            #[inline]
676            fn visit_u16<E: de::Error>(
677                self,
678                v: u16,
679            ) -> Result<crate::Timestamp, E> {
680                self.visit_i64(i64::from(v))
681            }
682
683            #[inline]
684            fn visit_i32<E: de::Error>(
685                self,
686                v: i32,
687            ) -> Result<crate::Timestamp, E> {
688                self.visit_i64(i64::from(v))
689            }
690
691            #[inline]
692            fn visit_u32<E: de::Error>(
693                self,
694                v: u32,
695            ) -> Result<crate::Timestamp, E> {
696                self.visit_i64(i64::from(v))
697            }
698
699            #[inline]
700            fn visit_i64<E: de::Error>(
701                self,
702                v: i64,
703            ) -> Result<crate::Timestamp, E> {
704                crate::Timestamp::from_millisecond(v)
705                    .map_err(de::Error::custom)
706            }
707
708            #[inline]
709            fn visit_u64<E: de::Error>(
710                self,
711                v: u64,
712            ) -> Result<crate::Timestamp, E> {
713                let v = i64::try_from(v).map_err(|_| {
714                    de::Error::custom(format_args!(
715                        "got unsigned integer {v} milliseconds, \
716                         which is too big to fit in a Jiff `Timestamp`",
717                    ))
718                })?;
719                self.visit_i64(v)
720            }
721
722            #[inline]
723            fn visit_i128<E: de::Error>(
724                self,
725                v: i128,
726            ) -> Result<crate::Timestamp, E> {
727                let v = i64::try_from(v).map_err(|_| {
728                    de::Error::custom(format_args!(
729                        "got signed integer {v} milliseconds, \
730                         which is too big to fit in a Jiff `Timestamp`",
731                    ))
732                })?;
733                self.visit_i64(v)
734            }
735
736            #[inline]
737            fn visit_u128<E: de::Error>(
738                self,
739                v: u128,
740            ) -> Result<crate::Timestamp, E> {
741                let v = i64::try_from(v).map_err(|_| {
742                    de::Error::custom(format_args!(
743                        "got unsigned integer {v} milliseconds, \
744                         which is too big to fit in a Jiff `Timestamp`",
745                    ))
746                })?;
747                self.visit_i64(v)
748            }
749        }
750
751        /// (De)serialize a required integer number of milliseconds from the
752        /// Unix epoch.
753        pub mod required {
754            /// Serialize a required integer number of milliseconds since the
755            /// Unix epoch.
756            #[inline]
757            pub fn serialize<S: serde::Serializer>(
758                timestamp: &crate::Timestamp,
759                se: S,
760            ) -> Result<S::Ok, S::Error> {
761                se.serialize_i64(timestamp.as_millisecond())
762            }
763
764            /// Deserialize a required integer number of milliseconds since the
765            /// Unix epoch.
766            #[inline]
767            pub fn deserialize<'de, D: serde::Deserializer<'de>>(
768                de: D,
769            ) -> Result<crate::Timestamp, D::Error> {
770                de.deserialize_i64(super::Visitor)
771            }
772        }
773
774        /// (De)serialize an optional integer number of milliseconds from the
775        /// Unix epoch.
776        pub mod optional {
777            /// Serialize an optional integer number of milliseconds since the
778            /// Unix epoch.
779            #[inline]
780            pub fn serialize<S: serde::Serializer>(
781                timestamp: &Option<crate::Timestamp>,
782                se: S,
783            ) -> Result<S::Ok, S::Error> {
784                match *timestamp {
785                    None => se.serialize_none(),
786                    Some(ts) => se.serialize_i64(ts.as_millisecond()),
787                }
788            }
789
790            /// Deserialize an optional integer number of milliseconds since
791            /// the Unix epoch.
792            #[inline]
793            pub fn deserialize<'de, D: serde::Deserializer<'de>>(
794                de: D,
795            ) -> Result<Option<crate::Timestamp>, D::Error> {
796                de.deserialize_option(super::super::OptionalVisitor(
797                    super::Visitor,
798                ))
799            }
800        }
801    }
802
803    /// (De)serialize an integer number of microseconds from the Unix epoch.
804    pub mod microsecond {
805        use serde::de;
806
807        struct Visitor;
808
809        impl<'de> de::Visitor<'de> for Visitor {
810            type Value = crate::Timestamp;
811
812            fn expecting(
813                &self,
814                f: &mut core::fmt::Formatter,
815            ) -> core::fmt::Result {
816                f.write_str(
817                    "an integer number of microseconds from the Unix epoch",
818                )
819            }
820
821            #[inline]
822            fn visit_i8<E: de::Error>(
823                self,
824                v: i8,
825            ) -> Result<crate::Timestamp, E> {
826                self.visit_i64(i64::from(v))
827            }
828
829            #[inline]
830            fn visit_u8<E: de::Error>(
831                self,
832                v: u8,
833            ) -> Result<crate::Timestamp, E> {
834                self.visit_i64(i64::from(v))
835            }
836
837            #[inline]
838            fn visit_i16<E: de::Error>(
839                self,
840                v: i16,
841            ) -> Result<crate::Timestamp, E> {
842                self.visit_i64(i64::from(v))
843            }
844
845            #[inline]
846            fn visit_u16<E: de::Error>(
847                self,
848                v: u16,
849            ) -> Result<crate::Timestamp, E> {
850                self.visit_i64(i64::from(v))
851            }
852
853            #[inline]
854            fn visit_i32<E: de::Error>(
855                self,
856                v: i32,
857            ) -> Result<crate::Timestamp, E> {
858                self.visit_i64(i64::from(v))
859            }
860
861            #[inline]
862            fn visit_u32<E: de::Error>(
863                self,
864                v: u32,
865            ) -> Result<crate::Timestamp, E> {
866                self.visit_i64(i64::from(v))
867            }
868
869            #[inline]
870            fn visit_i64<E: de::Error>(
871                self,
872                v: i64,
873            ) -> Result<crate::Timestamp, E> {
874                crate::Timestamp::from_microsecond(v)
875                    .map_err(de::Error::custom)
876            }
877
878            #[inline]
879            fn visit_u64<E: de::Error>(
880                self,
881                v: u64,
882            ) -> Result<crate::Timestamp, E> {
883                let v = i64::try_from(v).map_err(|_| {
884                    de::Error::custom(format_args!(
885                        "got unsigned integer {v} microseconds, \
886                         which is too big to fit in a Jiff `Timestamp`",
887                    ))
888                })?;
889                self.visit_i64(v)
890            }
891
892            #[inline]
893            fn visit_i128<E: de::Error>(
894                self,
895                v: i128,
896            ) -> Result<crate::Timestamp, E> {
897                let v = i64::try_from(v).map_err(|_| {
898                    de::Error::custom(format_args!(
899                        "got signed integer {v} microseconds, \
900                         which is too big to fit in a Jiff `Timestamp`",
901                    ))
902                })?;
903                self.visit_i64(v)
904            }
905
906            #[inline]
907            fn visit_u128<E: de::Error>(
908                self,
909                v: u128,
910            ) -> Result<crate::Timestamp, E> {
911                let v = i64::try_from(v).map_err(|_| {
912                    de::Error::custom(format_args!(
913                        "got unsigned integer {v} microseconds, \
914                         which is too big to fit in a Jiff `Timestamp`",
915                    ))
916                })?;
917                self.visit_i64(v)
918            }
919        }
920
921        /// (De)serialize a required integer number of microseconds from the
922        /// Unix epoch.
923        pub mod required {
924            /// Serialize a required integer number of microseconds since the
925            /// Unix epoch.
926            #[inline]
927            pub fn serialize<S: serde::Serializer>(
928                timestamp: &crate::Timestamp,
929                se: S,
930            ) -> Result<S::Ok, S::Error> {
931                se.serialize_i64(timestamp.as_microsecond())
932            }
933
934            /// Deserialize a required integer number of microseconds since the
935            /// Unix epoch.
936            #[inline]
937            pub fn deserialize<'de, D: serde::Deserializer<'de>>(
938                de: D,
939            ) -> Result<crate::Timestamp, D::Error> {
940                de.deserialize_i64(super::Visitor)
941            }
942        }
943
944        /// (De)serialize an optional integer number of microseconds from the
945        /// Unix epoch.
946        pub mod optional {
947            /// Serialize an optional integer number of microseconds since the
948            /// Unix epoch.
949            #[inline]
950            pub fn serialize<S: serde::Serializer>(
951                timestamp: &Option<crate::Timestamp>,
952                se: S,
953            ) -> Result<S::Ok, S::Error> {
954                match *timestamp {
955                    None => se.serialize_none(),
956                    Some(ts) => se.serialize_i64(ts.as_microsecond()),
957                }
958            }
959
960            /// Deserialize an optional integer number of microseconds since
961            /// the Unix epoch.
962            #[inline]
963            pub fn deserialize<'de, D: serde::Deserializer<'de>>(
964                de: D,
965            ) -> Result<Option<crate::Timestamp>, D::Error> {
966                de.deserialize_option(super::super::OptionalVisitor(
967                    super::Visitor,
968                ))
969            }
970        }
971    }
972
973    /// (De)serialize an integer number of nanoseconds from the Unix epoch.
974    pub mod nanosecond {
975        use serde::de;
976
977        struct Visitor;
978
979        impl<'de> de::Visitor<'de> for Visitor {
980            type Value = crate::Timestamp;
981
982            fn expecting(
983                &self,
984                f: &mut core::fmt::Formatter,
985            ) -> core::fmt::Result {
986                f.write_str(
987                    "an integer number of nanoseconds from the Unix epoch",
988                )
989            }
990
991            #[inline]
992            fn visit_i64<E: de::Error>(
993                self,
994                v: i64,
995            ) -> Result<crate::Timestamp, E> {
996                self.visit_i128(i128::from(v))
997            }
998
999            #[inline]
1000            fn visit_u64<E: de::Error>(
1001                self,
1002                v: u64,
1003            ) -> Result<crate::Timestamp, E> {
1004                self.visit_u128(u128::from(v))
1005            }
1006
1007            #[inline]
1008            fn visit_i128<E: de::Error>(
1009                self,
1010                v: i128,
1011            ) -> Result<crate::Timestamp, E> {
1012                crate::Timestamp::from_nanosecond(v).map_err(de::Error::custom)
1013            }
1014
1015            #[inline]
1016            fn visit_u128<E: de::Error>(
1017                self,
1018                v: u128,
1019            ) -> Result<crate::Timestamp, E> {
1020                let v = i128::try_from(v).map_err(|_| {
1021                    de::Error::custom(format_args!(
1022                        "got unsigned integer {v} nanoseconds, \
1023                         which is too big to fit in a Jiff `Timestamp`",
1024                    ))
1025                })?;
1026                self.visit_i128(v)
1027            }
1028        }
1029
1030        /// (De)serialize a required integer number of nanoseconds from the
1031        /// Unix epoch.
1032        pub mod required {
1033            /// Serialize a required integer number of nanoseconds since the
1034            /// Unix epoch.
1035            #[inline]
1036            pub fn serialize<S: serde::Serializer>(
1037                timestamp: &crate::Timestamp,
1038                se: S,
1039            ) -> Result<S::Ok, S::Error> {
1040                se.serialize_i128(timestamp.as_nanosecond())
1041            }
1042
1043            /// Deserialize a required integer number of nanoseconds since the
1044            /// Unix epoch.
1045            #[inline]
1046            pub fn deserialize<'de, D: serde::Deserializer<'de>>(
1047                de: D,
1048            ) -> Result<crate::Timestamp, D::Error> {
1049                de.deserialize_i128(super::Visitor)
1050            }
1051        }
1052
1053        /// (De)serialize an optional integer number of nanoseconds from the
1054        /// Unix epoch.
1055        pub mod optional {
1056            /// Serialize an optional integer number of nanoseconds since the
1057            /// Unix epoch.
1058            #[inline]
1059            pub fn serialize<S: serde::Serializer>(
1060                timestamp: &Option<crate::Timestamp>,
1061                se: S,
1062            ) -> Result<S::Ok, S::Error> {
1063                match *timestamp {
1064                    None => se.serialize_none(),
1065                    Some(ts) => se.serialize_i128(ts.as_nanosecond()),
1066                }
1067            }
1068
1069            /// Deserialize an optional integer number of nanoseconds since the
1070            /// Unix epoch.
1071            #[inline]
1072            pub fn deserialize<'de, D: serde::Deserializer<'de>>(
1073                de: D,
1074            ) -> Result<Option<crate::Timestamp>, D::Error> {
1075                de.deserialize_option(super::super::OptionalVisitor(
1076                    super::Visitor,
1077                ))
1078            }
1079        }
1080    }
1081}
1082
1083/// Convenience routines for (de)serializing [`TimeZone`](crate::tz::TimeZone)
1084/// values.
1085///
1086/// The `required` and `optional` sub-modules each provide serialization and
1087/// deserialization routines. They are meant to be used with Serde's
1088/// [`with` attribute].
1089///
1090/// # Advice
1091///
1092/// Serializing time zones is useful when you want to accept user configuration
1093/// selecting a time zone to use. This might be beneficial when one cannot rely
1094/// on a system's time zone.
1095///
1096/// Note that when deserializing time zones that are IANA time zone
1097/// identifiers, Jiff will automatically use the implicit global database to
1098/// resolve the identifier to an actual time zone. If you do not want to use
1099/// Jiff's global time zone database for this, you'll need to write your own
1100/// Serde integration.
1101///
1102/// [`with` attribute]: https://serde.rs/field-attrs.html#with
1103///
1104/// # Example
1105///
1106/// ```
1107/// use jiff::tz::TimeZone;
1108///
1109/// #[derive(Debug, serde::Deserialize, serde::Serialize)]
1110/// struct Record {
1111///     #[serde(with = "jiff::fmt::serde::tz::required")]
1112///     tz: TimeZone,
1113/// }
1114///
1115/// let json = r#"{"tz":"America/Nuuk"}"#;
1116/// let got: Record = serde_json::from_str(&json)?;
1117/// assert_eq!(got.tz, TimeZone::get("America/Nuuk")?);
1118/// assert_eq!(serde_json::to_string(&got)?, json);
1119///
1120/// # Ok::<(), Box<dyn std::error::Error>>(())
1121/// ```
1122///
1123/// # Example: serializing an unknown `TimeZone` works
1124///
1125/// For example, when a time zone was created from
1126/// [`TimeZone::system`](crate::tz::TimeZone::system) and a system configured
1127/// time zone could not be found. One can artifically create this situation
1128/// with [`TimeZone::unknown`](crate::tz::TimeZone::unknown):
1129///
1130/// ```
1131/// use jiff::tz::TimeZone;
1132///
1133/// #[derive(Debug, serde::Deserialize, serde::Serialize)]
1134/// struct Record {
1135///     #[serde(with = "jiff::fmt::serde::tz::required")]
1136///     tz: TimeZone,
1137/// }
1138///
1139/// let record = Record { tz: TimeZone::unknown() };
1140/// assert_eq!(
1141///     serde_json::to_string(&record)?,
1142///     r#"{"tz":"Etc/Unknown"}"#,
1143/// );
1144///
1145/// # Ok::<(), Box<dyn std::error::Error>>(())
1146/// ```
1147///
1148/// And it deserializes as well:
1149///
1150/// ```
1151/// use jiff::tz::TimeZone;
1152///
1153/// #[derive(Debug, serde::Deserialize, serde::Serialize)]
1154/// struct Record {
1155///     #[serde(with = "jiff::fmt::serde::tz::required")]
1156///     tz: TimeZone,
1157/// }
1158///
1159/// let json = r#"{"tz":"Etc/Unknown"}"#;
1160/// let got: Record = serde_json::from_str(&json)?;
1161/// assert!(got.tz.is_unknown());
1162///
1163/// # Ok::<(), Box<dyn std::error::Error>>(())
1164/// ```
1165///
1166/// An unknown time zone is "allowed" to percolate through Jiff because it's
1167/// usually not desirable to return an error and completely fail if a system
1168/// time zone could not be detected. On the other hand, by using a special
1169/// `Etc/Unknown` identifier for this case, it still surfaces the fact that
1170/// something has gone wrong.
1171pub mod tz {
1172    use serde::de;
1173
1174    use crate::fmt::{temporal, StdFmtWrite};
1175
1176    struct TemporalTimeZone<'a>(&'a crate::tz::TimeZone);
1177
1178    impl<'a> core::fmt::Display for TemporalTimeZone<'a> {
1179        fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
1180            static PRINTER: temporal::DateTimePrinter =
1181                temporal::DateTimePrinter::new();
1182            PRINTER
1183                .print_time_zone(self.0, StdFmtWrite(f))
1184                .map_err(|_| core::fmt::Error)
1185        }
1186    }
1187
1188    /// A required visitor for `TimeZone`.
1189    struct Visitor;
1190
1191    impl<'de> de::Visitor<'de> for Visitor {
1192        type Value = crate::tz::TimeZone;
1193
1194        fn expecting(
1195            &self,
1196            f: &mut core::fmt::Formatter,
1197        ) -> core::fmt::Result {
1198            f.write_str(
1199                "a string representing a time zone via an \
1200                 IANA time zone identifier, fixed offset from UTC \
1201                 or a POSIX time zone string",
1202            )
1203        }
1204
1205        #[inline]
1206        fn visit_bytes<E: de::Error>(
1207            self,
1208            value: &[u8],
1209        ) -> Result<crate::tz::TimeZone, E> {
1210            static PARSER: temporal::DateTimeParser =
1211                temporal::DateTimeParser::new();
1212            PARSER.parse_time_zone(value).map_err(de::Error::custom)
1213        }
1214
1215        #[inline]
1216        fn visit_str<E: de::Error>(
1217            self,
1218            value: &str,
1219        ) -> Result<crate::tz::TimeZone, E> {
1220            self.visit_bytes(value.as_bytes())
1221        }
1222    }
1223
1224    /// A generic optional visitor for `TimeZone`.
1225    struct OptionalVisitor<V>(V);
1226
1227    impl<'de, V: de::Visitor<'de, Value = crate::tz::TimeZone>>
1228        de::Visitor<'de> for OptionalVisitor<V>
1229    {
1230        type Value = Option<crate::tz::TimeZone>;
1231
1232        fn expecting(
1233            &self,
1234            f: &mut core::fmt::Formatter,
1235        ) -> core::fmt::Result {
1236            f.write_str(
1237                "a string representing a time zone via an \
1238                 IANA time zone identifier, fixed offset from UTC \
1239                 or a POSIX time zone string",
1240            )
1241        }
1242
1243        #[inline]
1244        fn visit_some<D: de::Deserializer<'de>>(
1245            self,
1246            de: D,
1247        ) -> Result<Option<crate::tz::TimeZone>, D::Error> {
1248            de.deserialize_str(self.0).map(Some)
1249        }
1250
1251        #[inline]
1252        fn visit_none<E: de::Error>(
1253            self,
1254        ) -> Result<Option<crate::tz::TimeZone>, E> {
1255            Ok(None)
1256        }
1257    }
1258
1259    /// (De)serialize a required [`TimeZone`](crate::tz::TimeZone).
1260    pub mod required {
1261        /// Serialize a required [`TimeZone`](crate::tz::TimeZone).
1262        ///
1263        /// This will result in an IANA time zone identifier, fixed offset or a
1264        /// POSIX time zone string.
1265        ///
1266        /// This can return an error in some cases when the `TimeZone` has no
1267        /// succinct string representation. For example, when the `TimeZone` is
1268        /// derived from a system `/etc/localtime` for which no IANA time zone
1269        /// identifier could be found.
1270        #[inline]
1271        pub fn serialize<S: serde::Serializer>(
1272            tz: &crate::tz::TimeZone,
1273            se: S,
1274        ) -> Result<S::Ok, S::Error> {
1275            if !tz.has_succinct_serialization() {
1276                return Err(<S::Error as serde::ser::Error>::custom(
1277                    "time zones without IANA identifiers that aren't either \
1278                     fixed offsets or a POSIX time zone can't be serialized \
1279                     (this typically occurs when this is a system time zone \
1280                      derived from `/etc/localtime` on Unix systems that \
1281                      isn't symlinked to an entry in `/usr/share/zoneinfo)",
1282                ));
1283            }
1284            se.collect_str(&super::TemporalTimeZone(tz))
1285        }
1286
1287        /// Deserialize a required [`TimeZone`](crate::tz::TimeZone).
1288        ///
1289        /// This will attempt to parse an IANA time zone identifier, a fixed
1290        /// offset or a POSIX time zone string.
1291        #[inline]
1292        pub fn deserialize<'de, D: serde::Deserializer<'de>>(
1293            de: D,
1294        ) -> Result<crate::tz::TimeZone, D::Error> {
1295            de.deserialize_str(super::Visitor)
1296        }
1297    }
1298
1299    /// (De)serialize an optional [`TimeZone`](crate::tz::TimeZone).
1300    pub mod optional {
1301        /// Serialize an optional [`TimeZone`](crate::tz::TimeZone).
1302        ///
1303        /// This will result in an IANA time zone identifier, fixed offset or a
1304        /// POSIX time zone string.
1305        ///
1306        /// This can return an error in some cases when the `TimeZone` has no
1307        /// succinct string representation. For example, when the `TimeZone` is
1308        /// derived from a system `/etc/localtime` for which no IANA time zone
1309        /// identifier could be found.
1310        #[inline]
1311        pub fn serialize<S: serde::Serializer>(
1312            tz: &Option<crate::tz::TimeZone>,
1313            se: S,
1314        ) -> Result<S::Ok, S::Error> {
1315            match *tz {
1316                None => se.serialize_none(),
1317                Some(ref tz) => super::required::serialize(tz, se),
1318            }
1319        }
1320
1321        /// Deserialize an optional [`TimeZone`](crate::tz::TimeZone).
1322        ///
1323        /// This will attempt to parse an IANA time zone identifier, a fixed
1324        /// offset or a POSIX time zone string.
1325        #[inline]
1326        pub fn deserialize<'de, D: serde::Deserializer<'de>>(
1327            de: D,
1328        ) -> Result<Option<crate::tz::TimeZone>, D::Error> {
1329            de.deserialize_option(super::OptionalVisitor(super::Visitor))
1330        }
1331    }
1332}
1333
1334#[cfg(test)]
1335mod tests {
1336    use crate::{
1337        span::span_eq, SignedDuration, Span, SpanFieldwise, Timestamp, ToSpan,
1338    };
1339
1340    #[test]
1341    fn duration_friendly_compact_required() {
1342        #[derive(Debug, serde::Deserialize, serde::Serialize)]
1343        struct Data {
1344            #[serde(
1345                serialize_with = "crate::fmt::serde::duration::friendly::compact::required"
1346            )]
1347            duration: SignedDuration,
1348        }
1349
1350        let json = r#"{"duration":"36 hours 1100ms"}"#;
1351        let got: Data = serde_json::from_str(&json).unwrap();
1352        assert_eq!(
1353            got.duration,
1354            SignedDuration::new(36 * 60 * 60 + 1, 100_000_000)
1355        );
1356
1357        let expected = r#"{"duration":"36h 1s 100ms"}"#;
1358        assert_eq!(serde_json::to_string(&got).unwrap(), expected);
1359    }
1360
1361    #[test]
1362    fn duration_friendly_compact_optional() {
1363        #[derive(Debug, serde::Deserialize, serde::Serialize)]
1364        struct Data {
1365            #[serde(
1366                serialize_with = "crate::fmt::serde::duration::friendly::compact::optional"
1367            )]
1368            duration: Option<SignedDuration>,
1369        }
1370
1371        let json = r#"{"duration":"36 hours 1100ms"}"#;
1372        let got: Data = serde_json::from_str(&json).unwrap();
1373        assert_eq!(
1374            got.duration,
1375            Some(SignedDuration::new(36 * 60 * 60 + 1, 100_000_000))
1376        );
1377
1378        let expected = r#"{"duration":"36h 1s 100ms"}"#;
1379        assert_eq!(serde_json::to_string(&got).unwrap(), expected);
1380    }
1381
1382    #[test]
1383    fn span_friendly_compact_required() {
1384        #[derive(Debug, serde::Deserialize, serde::Serialize)]
1385        struct Data {
1386            #[serde(
1387                serialize_with = "crate::fmt::serde::span::friendly::compact::required"
1388            )]
1389            span: Span,
1390        }
1391
1392        let json = r#"{"span":"1 year 2 months 36 hours 1100ms"}"#;
1393        let got: Data = serde_json::from_str(&json).unwrap();
1394        span_eq!(got.span, 1.year().months(2).hours(36).milliseconds(1100));
1395
1396        let expected = r#"{"span":"1y 2mo 36h 1100ms"}"#;
1397        assert_eq!(serde_json::to_string(&got).unwrap(), expected);
1398    }
1399
1400    #[test]
1401    fn span_friendly_compact_optional() {
1402        #[derive(Debug, serde::Deserialize, serde::Serialize)]
1403        struct Data {
1404            #[serde(
1405                serialize_with = "crate::fmt::serde::span::friendly::compact::optional"
1406            )]
1407            span: Option<Span>,
1408        }
1409
1410        let json = r#"{"span":"1 year 2 months 36 hours 1100ms"}"#;
1411        let got: Data = serde_json::from_str(&json).unwrap();
1412        assert_eq!(
1413            got.span.map(SpanFieldwise),
1414            Some(1.year().months(2).hours(36).milliseconds(1100).fieldwise())
1415        );
1416
1417        let expected = r#"{"span":"1y 2mo 36h 1100ms"}"#;
1418        assert_eq!(serde_json::to_string(&got).unwrap(), expected);
1419    }
1420
1421    #[test]
1422    fn timestamp_second_required() {
1423        #[derive(Debug, serde::Deserialize, serde::Serialize)]
1424        struct Data {
1425            #[serde(with = "crate::fmt::serde::timestamp::second::required")]
1426            ts: Timestamp,
1427        }
1428
1429        let json = r#"{"ts":1517644800}"#;
1430        let got: Data = serde_json::from_str(&json).unwrap();
1431        assert_eq!(got.ts, Timestamp::from_second(1517644800).unwrap());
1432        assert_eq!(serde_json::to_string(&got).unwrap(), json);
1433    }
1434
1435    #[test]
1436    fn timestamp_second_optional() {
1437        #[derive(Debug, serde::Deserialize, serde::Serialize)]
1438        struct Data {
1439            #[serde(with = "crate::fmt::serde::timestamp::second::optional")]
1440            ts: Option<Timestamp>,
1441        }
1442
1443        let json = r#"{"ts":1517644800}"#;
1444        let got: Data = serde_json::from_str(&json).unwrap();
1445        assert_eq!(got.ts, Some(Timestamp::from_second(1517644800).unwrap()));
1446        assert_eq!(serde_json::to_string(&got).unwrap(), json);
1447    }
1448
1449    #[test]
1450    fn timestamp_millisecond_required() {
1451        #[derive(Debug, serde::Deserialize, serde::Serialize)]
1452        struct Data {
1453            #[serde(
1454                with = "crate::fmt::serde::timestamp::millisecond::required"
1455            )]
1456            ts: Timestamp,
1457        }
1458
1459        let json = r#"{"ts":1517644800000}"#;
1460        let got: Data = serde_json::from_str(&json).unwrap();
1461        assert_eq!(
1462            got.ts,
1463            Timestamp::from_millisecond(1517644800_000).unwrap()
1464        );
1465        assert_eq!(serde_json::to_string(&got).unwrap(), json);
1466
1467        let json = r#"{"ts":1517644800123}"#;
1468        let got: Data = serde_json::from_str(&json).unwrap();
1469        assert_eq!(
1470            got.ts,
1471            Timestamp::from_millisecond(1517644800_123).unwrap()
1472        );
1473        assert_eq!(serde_json::to_string(&got).unwrap(), json);
1474    }
1475
1476    #[test]
1477    fn timestamp_millisecond_optional() {
1478        #[derive(Debug, serde::Deserialize, serde::Serialize)]
1479        struct Data {
1480            #[serde(
1481                with = "crate::fmt::serde::timestamp::millisecond::optional"
1482            )]
1483            ts: Option<Timestamp>,
1484        }
1485
1486        let json = r#"{"ts":1517644800000}"#;
1487        let got: Data = serde_json::from_str(&json).unwrap();
1488        assert_eq!(
1489            got.ts,
1490            Some(Timestamp::from_millisecond(1517644800_000).unwrap())
1491        );
1492        assert_eq!(serde_json::to_string(&got).unwrap(), json);
1493
1494        let json = r#"{"ts":1517644800123}"#;
1495        let got: Data = serde_json::from_str(&json).unwrap();
1496        assert_eq!(
1497            got.ts,
1498            Some(Timestamp::from_millisecond(1517644800_123).unwrap())
1499        );
1500        assert_eq!(serde_json::to_string(&got).unwrap(), json);
1501    }
1502
1503    #[test]
1504    fn timestamp_microsecond_required() {
1505        #[derive(Debug, serde::Deserialize, serde::Serialize)]
1506        struct Data {
1507            #[serde(
1508                with = "crate::fmt::serde::timestamp::microsecond::required"
1509            )]
1510            ts: Timestamp,
1511        }
1512
1513        let json = r#"{"ts":1517644800000000}"#;
1514        let got: Data = serde_json::from_str(&json).unwrap();
1515        assert_eq!(
1516            got.ts,
1517            Timestamp::from_microsecond(1517644800_000000).unwrap()
1518        );
1519        assert_eq!(serde_json::to_string(&got).unwrap(), json);
1520
1521        let json = r#"{"ts":1517644800123456}"#;
1522        let got: Data = serde_json::from_str(&json).unwrap();
1523        assert_eq!(
1524            got.ts,
1525            Timestamp::from_microsecond(1517644800_123456).unwrap()
1526        );
1527        assert_eq!(serde_json::to_string(&got).unwrap(), json);
1528    }
1529
1530    #[test]
1531    fn timestamp_microsecond_optional() {
1532        #[derive(Debug, serde::Deserialize, serde::Serialize)]
1533        struct Data {
1534            #[serde(
1535                with = "crate::fmt::serde::timestamp::microsecond::optional"
1536            )]
1537            ts: Option<Timestamp>,
1538        }
1539
1540        let json = r#"{"ts":1517644800000000}"#;
1541        let got: Data = serde_json::from_str(&json).unwrap();
1542        assert_eq!(
1543            got.ts,
1544            Some(Timestamp::from_microsecond(1517644800_000000).unwrap())
1545        );
1546        assert_eq!(serde_json::to_string(&got).unwrap(), json);
1547
1548        let json = r#"{"ts":1517644800123456}"#;
1549        let got: Data = serde_json::from_str(&json).unwrap();
1550        assert_eq!(
1551            got.ts,
1552            Some(Timestamp::from_microsecond(1517644800_123456).unwrap())
1553        );
1554        assert_eq!(serde_json::to_string(&got).unwrap(), json);
1555    }
1556
1557    #[test]
1558    fn timestamp_nanosecond_required() {
1559        #[derive(Debug, serde::Deserialize, serde::Serialize)]
1560        struct Data {
1561            #[serde(
1562                with = "crate::fmt::serde::timestamp::nanosecond::required"
1563            )]
1564            ts: Timestamp,
1565        }
1566
1567        let json = r#"{"ts":1517644800000000000}"#;
1568        let got: Data = serde_json::from_str(&json).unwrap();
1569        assert_eq!(
1570            got.ts,
1571            Timestamp::from_nanosecond(1517644800_000000000).unwrap()
1572        );
1573        assert_eq!(serde_json::to_string(&got).unwrap(), json);
1574
1575        let json = r#"{"ts":1517644800123456789}"#;
1576        let got: Data = serde_json::from_str(&json).unwrap();
1577        assert_eq!(
1578            got.ts,
1579            Timestamp::from_nanosecond(1517644800_123456789).unwrap()
1580        );
1581        assert_eq!(serde_json::to_string(&got).unwrap(), json);
1582    }
1583
1584    #[test]
1585    fn timestamp_nanosecond_optional() {
1586        #[derive(Debug, serde::Deserialize, serde::Serialize)]
1587        struct Data {
1588            #[serde(
1589                with = "crate::fmt::serde::timestamp::nanosecond::optional"
1590            )]
1591            ts: Option<Timestamp>,
1592        }
1593
1594        let json = r#"{"ts":1517644800000000000}"#;
1595        let got: Data = serde_json::from_str(&json).unwrap();
1596        assert_eq!(
1597            got.ts,
1598            Some(Timestamp::from_nanosecond(1517644800_000000000).unwrap())
1599        );
1600        assert_eq!(serde_json::to_string(&got).unwrap(), json);
1601
1602        let json = r#"{"ts":1517644800123456789}"#;
1603        let got: Data = serde_json::from_str(&json).unwrap();
1604        assert_eq!(
1605            got.ts,
1606            Some(Timestamp::from_nanosecond(1517644800_123456789).unwrap())
1607        );
1608        assert_eq!(serde_json::to_string(&got).unwrap(), json);
1609    }
1610}