serde_with/
time_0_3.rs

1//! De/Serialization of [time v0.3][time] types
2//!
3//! This modules is only available if using the `time_0_3` feature of the crate.
4//! No extra types are exposed. Instead it enables support for [`time_0_3::Duration`] together with [`DurationSeconds`] and its variants.
5//! The types [`time_0_3::PrimitiveDateTime`] and [`time_0_3::OffsetDateTime`] are supported by [`TimestampSeconds`] and its variants.
6//! The well-known format descriptions [`Rfc2822`], [`Rfc3339`] and [`Iso8601`] are supported for [`OffsetDateTime`].
7//!
8//! [time]: https://docs.rs/time/0.3/
9
10// Serialization of large numbers can result in overflows
11// The time calculations are prone to this, so lint here extra
12// https://github.com/jonasbb/serde_with/issues/771
13#![warn(clippy::as_conversions)]
14
15use crate::{
16    formats::{Flexible, Format, Strict, Strictness},
17    prelude::*,
18};
19#[cfg(feature = "std")]
20use ::time_0_3::format_description::well_known::{
21    iso8601::EncodedConfig, Iso8601, Rfc2822, Rfc3339,
22};
23use ::time_0_3::{Duration as Time03Duration, OffsetDateTime, PrimitiveDateTime};
24
25/// Create a [`PrimitiveDateTime`] for the Unix Epoch
26fn unix_epoch_primitive() -> PrimitiveDateTime {
27    PrimitiveDateTime::new(
28        ::time_0_3::Date::from_ordinal_date(1970, 1).unwrap(),
29        ::time_0_3::Time::from_hms_nano(0, 0, 0, 0).unwrap(),
30    )
31}
32
33/// Convert a [`time::Duration`][time_0_3::Duration] into a [`DurationSigned`]
34fn duration_into_duration_signed(dur: &Time03Duration) -> DurationSigned {
35    let std_dur = Duration::new(
36        dur.whole_seconds().unsigned_abs(),
37        dur.subsec_nanoseconds().unsigned_abs(),
38    );
39
40    DurationSigned::with_duration(
41        // A duration of 0 is not positive, so check for negative value.
42        if dur.is_negative() {
43            Sign::Negative
44        } else {
45            Sign::Positive
46        },
47        std_dur,
48    )
49}
50
51/// Convert a [`DurationSigned`] into a [`time_0_3::Duration`]
52fn duration_from_duration_signed<'de, D>(sdur: DurationSigned) -> Result<Time03Duration, D::Error>
53where
54    D: Deserializer<'de>,
55{
56    let mut dur: Time03Duration = match sdur.duration.try_into() {
57        Ok(dur) => dur,
58        Err(msg) => {
59            return Err(DeError::custom(format_args!(
60                "Duration is outside of the representable range: {msg}"
61            )))
62        }
63    };
64    if sdur.sign.is_negative() {
65        dur = -dur;
66    }
67    Ok(dur)
68}
69
70macro_rules! use_duration_signed_ser {
71    (
72        $main_trait:ident $internal_trait:ident =>
73        {
74            $ty:ty; $converter:ident =>
75            $({
76                $format:ty, $strictness:ty =>
77                $($tbound:ident: $bound:ident $(,)?)*
78            })*
79        }
80    ) => {
81        $(
82            impl<$($tbound ,)*> SerializeAs<$ty> for $main_trait<$format, $strictness>
83            where
84                $($tbound: $bound,)*
85            {
86                fn serialize_as<S>(source: &$ty, serializer: S) -> Result<S::Ok, S::Error>
87                where
88                    S: Serializer,
89                {
90                    let dur: DurationSigned = $converter(source);
91                    $internal_trait::<$format, $strictness>::serialize_as(
92                        &dur,
93                        serializer,
94                    )
95                }
96            }
97        )*
98    };
99    (
100        $( $main_trait:ident $internal_trait:ident, )+ => $rest:tt
101    ) => {
102        $( use_duration_signed_ser!($main_trait $internal_trait => $rest); )+
103    };
104}
105
106fn offset_datetime_to_duration(source: &OffsetDateTime) -> DurationSigned {
107    duration_into_duration_signed(&(*source - OffsetDateTime::UNIX_EPOCH))
108}
109
110fn primitive_datetime_to_duration(source: &PrimitiveDateTime) -> DurationSigned {
111    duration_into_duration_signed(&(*source - unix_epoch_primitive()))
112}
113
114use_duration_signed_ser!(
115    DurationSeconds DurationSeconds,
116    DurationMilliSeconds DurationMilliSeconds,
117    DurationMicroSeconds DurationMicroSeconds,
118    DurationNanoSeconds DurationNanoSeconds,
119    => {
120        Time03Duration; duration_into_duration_signed =>
121        {i64, STRICTNESS => STRICTNESS: Strictness}
122    }
123);
124#[cfg(feature = "alloc")]
125use_duration_signed_ser!(
126    DurationSeconds DurationSeconds,
127    DurationMilliSeconds DurationMilliSeconds,
128    DurationMicroSeconds DurationMicroSeconds,
129    DurationNanoSeconds DurationNanoSeconds,
130    => {
131        Time03Duration; duration_into_duration_signed =>
132        {String, STRICTNESS => STRICTNESS: Strictness}
133    }
134);
135#[cfg(feature = "std")]
136use_duration_signed_ser!(
137    DurationSeconds DurationSeconds,
138    DurationMilliSeconds DurationMilliSeconds,
139    DurationMicroSeconds DurationMicroSeconds,
140    DurationNanoSeconds DurationNanoSeconds,
141    => {
142        Time03Duration; duration_into_duration_signed =>
143        {f64, STRICTNESS => STRICTNESS: Strictness}
144    }
145);
146use_duration_signed_ser!(
147    TimestampSeconds DurationSeconds,
148    TimestampMilliSeconds DurationMilliSeconds,
149    TimestampMicroSeconds DurationMicroSeconds,
150    TimestampNanoSeconds DurationNanoSeconds,
151    => {
152        OffsetDateTime; offset_datetime_to_duration =>
153        {i64, STRICTNESS => STRICTNESS: Strictness}
154    }
155);
156#[cfg(feature = "alloc")]
157use_duration_signed_ser!(
158    TimestampSeconds DurationSeconds,
159    TimestampMilliSeconds DurationMilliSeconds,
160    TimestampMicroSeconds DurationMicroSeconds,
161    TimestampNanoSeconds DurationNanoSeconds,
162    => {
163        OffsetDateTime; offset_datetime_to_duration =>
164        {String, STRICTNESS => STRICTNESS: Strictness}
165    }
166);
167#[cfg(feature = "std")]
168use_duration_signed_ser!(
169    TimestampSeconds DurationSeconds,
170    TimestampMilliSeconds DurationMilliSeconds,
171    TimestampMicroSeconds DurationMicroSeconds,
172    TimestampNanoSeconds DurationNanoSeconds,
173    => {
174        OffsetDateTime; offset_datetime_to_duration =>
175        {f64, STRICTNESS => STRICTNESS: Strictness}
176    }
177);
178use_duration_signed_ser!(
179    TimestampSeconds DurationSeconds,
180    TimestampMilliSeconds DurationMilliSeconds,
181    TimestampMicroSeconds DurationMicroSeconds,
182    TimestampNanoSeconds DurationNanoSeconds,
183    => {
184        PrimitiveDateTime; primitive_datetime_to_duration =>
185        {i64, STRICTNESS => STRICTNESS: Strictness}
186    }
187);
188#[cfg(feature = "alloc")]
189use_duration_signed_ser!(
190    TimestampSeconds DurationSeconds,
191    TimestampMilliSeconds DurationMilliSeconds,
192    TimestampMicroSeconds DurationMicroSeconds,
193    TimestampNanoSeconds DurationNanoSeconds,
194    => {
195        PrimitiveDateTime; primitive_datetime_to_duration =>
196        {String, STRICTNESS => STRICTNESS: Strictness}
197    }
198);
199#[cfg(feature = "std")]
200use_duration_signed_ser!(
201    TimestampSeconds DurationSeconds,
202    TimestampMilliSeconds DurationMilliSeconds,
203    TimestampMicroSeconds DurationMicroSeconds,
204    TimestampNanoSeconds DurationNanoSeconds,
205    => {
206        PrimitiveDateTime; primitive_datetime_to_duration =>
207        {f64, STRICTNESS => STRICTNESS: Strictness}
208    }
209);
210
211// Duration/Timestamp WITH FRACTIONS
212#[cfg(feature = "alloc")]
213use_duration_signed_ser!(
214    DurationSecondsWithFrac DurationSecondsWithFrac,
215    DurationMilliSecondsWithFrac DurationMilliSecondsWithFrac,
216    DurationMicroSecondsWithFrac DurationMicroSecondsWithFrac,
217    DurationNanoSecondsWithFrac DurationNanoSecondsWithFrac,
218    => {
219        Time03Duration; duration_into_duration_signed =>
220        {String, STRICTNESS => STRICTNESS: Strictness}
221    }
222);
223#[cfg(feature = "std")]
224use_duration_signed_ser!(
225    DurationSecondsWithFrac DurationSecondsWithFrac,
226    DurationMilliSecondsWithFrac DurationMilliSecondsWithFrac,
227    DurationMicroSecondsWithFrac DurationMicroSecondsWithFrac,
228    DurationNanoSecondsWithFrac DurationNanoSecondsWithFrac,
229    => {
230        Time03Duration; duration_into_duration_signed =>
231        {f64, STRICTNESS => STRICTNESS: Strictness}
232    }
233);
234#[cfg(feature = "alloc")]
235use_duration_signed_ser!(
236    TimestampSecondsWithFrac DurationSecondsWithFrac,
237    TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
238    TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
239    TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
240    => {
241        OffsetDateTime; offset_datetime_to_duration =>
242        {String, STRICTNESS => STRICTNESS: Strictness}
243    }
244);
245#[cfg(feature = "std")]
246use_duration_signed_ser!(
247    TimestampSecondsWithFrac DurationSecondsWithFrac,
248    TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
249    TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
250    TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
251    => {
252        OffsetDateTime; offset_datetime_to_duration =>
253        {f64, STRICTNESS => STRICTNESS: Strictness}
254    }
255);
256#[cfg(feature = "alloc")]
257use_duration_signed_ser!(
258    TimestampSecondsWithFrac DurationSecondsWithFrac,
259    TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
260    TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
261    TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
262    => {
263        PrimitiveDateTime; primitive_datetime_to_duration =>
264        {String, STRICTNESS => STRICTNESS: Strictness}
265    }
266);
267#[cfg(feature = "std")]
268use_duration_signed_ser!(
269    TimestampSecondsWithFrac DurationSecondsWithFrac,
270    TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
271    TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
272    TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
273    => {
274        PrimitiveDateTime; primitive_datetime_to_duration =>
275        {f64, STRICTNESS => STRICTNESS: Strictness}
276    }
277);
278
279macro_rules! use_duration_signed_de {
280    (
281        $main_trait:ident $internal_trait:ident =>
282        {
283            $ty:ty; $converter:ident =>
284            $({
285                $format:ty, $strictness:ty =>
286                $($tbound:ident: $bound:ident)*
287            })*
288        }
289    ) =>{
290        $(
291            impl<'de, $($tbound,)*> DeserializeAs<'de, $ty> for $main_trait<$format, $strictness>
292            where
293                $($tbound: $bound,)*
294            {
295                fn deserialize_as<D>(deserializer: D) -> Result<$ty, D::Error>
296                where
297                    D: Deserializer<'de>,
298                {
299                    let dur: DurationSigned = $internal_trait::<$format, $strictness>::deserialize_as(deserializer)?;
300                    $converter::<D>(dur)
301                }
302            }
303        )*
304    };
305    (
306        $( $main_trait:ident $internal_trait:ident, )+ => $rest:tt
307    ) => {
308        $( use_duration_signed_de!($main_trait $internal_trait => $rest); )+
309    };
310}
311
312fn duration_to_offset_datetime<'de, D>(dur: DurationSigned) -> Result<OffsetDateTime, D::Error>
313where
314    D: Deserializer<'de>,
315{
316    Ok(OffsetDateTime::UNIX_EPOCH + duration_from_duration_signed::<D>(dur)?)
317}
318
319fn duration_to_primitive_datetime<'de, D>(
320    dur: DurationSigned,
321) -> Result<PrimitiveDateTime, D::Error>
322where
323    D: Deserializer<'de>,
324{
325    Ok(unix_epoch_primitive() + duration_from_duration_signed::<D>(dur)?)
326}
327
328// No sub-second precision
329use_duration_signed_de!(
330    DurationSeconds DurationSeconds,
331    DurationMilliSeconds DurationMilliSeconds,
332    DurationMicroSeconds DurationMicroSeconds,
333    DurationNanoSeconds DurationNanoSeconds,
334    => {
335        Time03Duration; duration_from_duration_signed =>
336        {i64, Strict =>}
337        {FORMAT, Flexible => FORMAT: Format}
338    }
339);
340#[cfg(feature = "alloc")]
341use_duration_signed_de!(
342    DurationSeconds DurationSeconds,
343    DurationMilliSeconds DurationMilliSeconds,
344    DurationMicroSeconds DurationMicroSeconds,
345    DurationNanoSeconds DurationNanoSeconds,
346    => {
347        Time03Duration; duration_from_duration_signed =>
348        {String, Strict =>}
349    }
350);
351#[cfg(feature = "std")]
352use_duration_signed_de!(
353    DurationSeconds DurationSeconds,
354    DurationMilliSeconds DurationMilliSeconds,
355    DurationMicroSeconds DurationMicroSeconds,
356    DurationNanoSeconds DurationNanoSeconds,
357    => {
358        Time03Duration; duration_from_duration_signed =>
359        {f64, Strict =>}
360    }
361);
362use_duration_signed_de!(
363    TimestampSeconds DurationSeconds,
364    TimestampMilliSeconds DurationMilliSeconds,
365    TimestampMicroSeconds DurationMicroSeconds,
366    TimestampNanoSeconds DurationNanoSeconds,
367    => {
368        OffsetDateTime; duration_to_offset_datetime =>
369        {i64, Strict =>}
370        {FORMAT, Flexible => FORMAT: Format}
371    }
372);
373#[cfg(feature = "alloc")]
374use_duration_signed_de!(
375    TimestampSeconds DurationSeconds,
376    TimestampMilliSeconds DurationMilliSeconds,
377    TimestampMicroSeconds DurationMicroSeconds,
378    TimestampNanoSeconds DurationNanoSeconds,
379    => {
380        OffsetDateTime; duration_to_offset_datetime =>
381        {String, Strict =>}
382    }
383);
384#[cfg(feature = "std")]
385use_duration_signed_de!(
386    TimestampSeconds DurationSeconds,
387    TimestampMilliSeconds DurationMilliSeconds,
388    TimestampMicroSeconds DurationMicroSeconds,
389    TimestampNanoSeconds DurationNanoSeconds,
390    => {
391        OffsetDateTime; duration_to_offset_datetime =>
392        {f64, Strict =>}
393    }
394);
395use_duration_signed_de!(
396    TimestampSeconds DurationSeconds,
397    TimestampMilliSeconds DurationMilliSeconds,
398    TimestampMicroSeconds DurationMicroSeconds,
399    TimestampNanoSeconds DurationNanoSeconds,
400    => {
401        PrimitiveDateTime; duration_to_primitive_datetime =>
402        {i64, Strict =>}
403        {FORMAT, Flexible => FORMAT: Format}
404    }
405);
406#[cfg(feature = "alloc")]
407use_duration_signed_de!(
408    TimestampSeconds DurationSeconds,
409    TimestampMilliSeconds DurationMilliSeconds,
410    TimestampMicroSeconds DurationMicroSeconds,
411    TimestampNanoSeconds DurationNanoSeconds,
412    => {
413        PrimitiveDateTime; duration_to_primitive_datetime =>
414        {String, Strict =>}
415    }
416);
417#[cfg(feature = "std")]
418use_duration_signed_de!(
419    TimestampSeconds DurationSeconds,
420    TimestampMilliSeconds DurationMilliSeconds,
421    TimestampMicroSeconds DurationMicroSeconds,
422    TimestampNanoSeconds DurationNanoSeconds,
423    => {
424        PrimitiveDateTime; duration_to_primitive_datetime =>
425        {f64, Strict =>}
426    }
427);
428
429// Duration/Timestamp WITH FRACTIONS
430use_duration_signed_de!(
431    DurationSecondsWithFrac DurationSecondsWithFrac,
432    DurationMilliSecondsWithFrac DurationMilliSecondsWithFrac,
433    DurationMicroSecondsWithFrac DurationMicroSecondsWithFrac,
434    DurationNanoSecondsWithFrac DurationNanoSecondsWithFrac,
435    => {
436        Time03Duration; duration_from_duration_signed =>
437        {FORMAT, Flexible => FORMAT: Format}
438    }
439);
440#[cfg(feature = "alloc")]
441use_duration_signed_de!(
442    DurationSecondsWithFrac DurationSecondsWithFrac,
443    DurationMilliSecondsWithFrac DurationMilliSecondsWithFrac,
444    DurationMicroSecondsWithFrac DurationMicroSecondsWithFrac,
445    DurationNanoSecondsWithFrac DurationNanoSecondsWithFrac,
446    => {
447        Time03Duration; duration_from_duration_signed =>
448        {String, Strict =>}
449    }
450);
451#[cfg(feature = "std")]
452use_duration_signed_de!(
453    DurationSecondsWithFrac DurationSecondsWithFrac,
454    DurationMilliSecondsWithFrac DurationMilliSecondsWithFrac,
455    DurationMicroSecondsWithFrac DurationMicroSecondsWithFrac,
456    DurationNanoSecondsWithFrac DurationNanoSecondsWithFrac,
457    => {
458        Time03Duration; duration_from_duration_signed =>
459        {f64, Strict =>}
460    }
461);
462use_duration_signed_de!(
463    TimestampSecondsWithFrac DurationSecondsWithFrac,
464    TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
465    TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
466    TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
467    => {
468        OffsetDateTime; duration_to_offset_datetime =>
469        {FORMAT, Flexible => FORMAT: Format}
470    }
471);
472#[cfg(feature = "alloc")]
473use_duration_signed_de!(
474    TimestampSecondsWithFrac DurationSecondsWithFrac,
475    TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
476    TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
477    TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
478    => {
479        OffsetDateTime; duration_to_offset_datetime =>
480        {String, Strict =>}
481    }
482);
483#[cfg(feature = "std")]
484use_duration_signed_de!(
485    TimestampSecondsWithFrac DurationSecondsWithFrac,
486    TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
487    TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
488    TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
489    => {
490        OffsetDateTime; duration_to_offset_datetime =>
491        {f64, Strict =>}
492    }
493);
494use_duration_signed_de!(
495    TimestampSecondsWithFrac DurationSecondsWithFrac,
496    TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
497    TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
498    TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
499    => {
500        PrimitiveDateTime; duration_to_primitive_datetime =>
501        {FORMAT, Flexible => FORMAT: Format}
502    }
503);
504#[cfg(feature = "alloc")]
505use_duration_signed_de!(
506    TimestampSecondsWithFrac DurationSecondsWithFrac,
507    TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
508    TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
509    TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
510    => {
511        PrimitiveDateTime; duration_to_primitive_datetime =>
512        {String, Strict =>}
513    }
514);
515#[cfg(feature = "std")]
516use_duration_signed_de!(
517    TimestampSecondsWithFrac DurationSecondsWithFrac,
518    TimestampMilliSecondsWithFrac DurationMilliSecondsWithFrac,
519    TimestampMicroSecondsWithFrac DurationMicroSecondsWithFrac,
520    TimestampNanoSecondsWithFrac DurationNanoSecondsWithFrac,
521    => {
522        PrimitiveDateTime; duration_to_primitive_datetime =>
523        {f64, Strict =>}
524    }
525);
526
527#[cfg(feature = "std")]
528impl SerializeAs<OffsetDateTime> for Rfc2822 {
529    fn serialize_as<S>(datetime: &OffsetDateTime, serializer: S) -> Result<S::Ok, S::Error>
530    where
531        S: Serializer,
532    {
533        datetime
534            .format(&Rfc2822)
535            .map_err(S::Error::custom)?
536            .serialize(serializer)
537    }
538}
539
540#[cfg(feature = "std")]
541impl<'de> DeserializeAs<'de, OffsetDateTime> for Rfc2822 {
542    fn deserialize_as<D>(deserializer: D) -> Result<OffsetDateTime, D::Error>
543    where
544        D: Deserializer<'de>,
545    {
546        struct Helper;
547        impl Visitor<'_> for Helper {
548            type Value = OffsetDateTime;
549
550            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
551                formatter.write_str("a RFC2822-formatted `OffsetDateTime`")
552            }
553
554            fn visit_str<E: DeError>(self, value: &str) -> Result<Self::Value, E> {
555                Self::Value::parse(value, &Rfc2822).map_err(E::custom)
556            }
557        }
558
559        deserializer.deserialize_str(Helper)
560    }
561}
562
563#[cfg(feature = "std")]
564impl SerializeAs<OffsetDateTime> for Rfc3339 {
565    fn serialize_as<S>(datetime: &OffsetDateTime, serializer: S) -> Result<S::Ok, S::Error>
566    where
567        S: Serializer,
568    {
569        datetime
570            .format(&Rfc3339)
571            .map_err(S::Error::custom)?
572            .serialize(serializer)
573    }
574}
575
576#[cfg(feature = "std")]
577impl<'de> DeserializeAs<'de, OffsetDateTime> for Rfc3339 {
578    fn deserialize_as<D>(deserializer: D) -> Result<OffsetDateTime, D::Error>
579    where
580        D: Deserializer<'de>,
581    {
582        struct Helper;
583        impl Visitor<'_> for Helper {
584            type Value = OffsetDateTime;
585
586            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
587                formatter.write_str("a RFC3339-formatted `OffsetDateTime`")
588            }
589
590            fn visit_str<E: DeError>(self, value: &str) -> Result<Self::Value, E> {
591                Self::Value::parse(value, &Rfc3339).map_err(E::custom)
592            }
593        }
594
595        deserializer.deserialize_str(Helper)
596    }
597}
598
599#[cfg(feature = "std")]
600impl<const CONFIG: EncodedConfig> SerializeAs<OffsetDateTime> for Iso8601<CONFIG> {
601    fn serialize_as<S>(datetime: &OffsetDateTime, serializer: S) -> Result<S::Ok, S::Error>
602    where
603        S: Serializer,
604    {
605        datetime
606            .format(&Iso8601::<CONFIG>)
607            .map_err(S::Error::custom)?
608            .serialize(serializer)
609    }
610}
611
612#[cfg(feature = "std")]
613impl<'de, const CONFIG: EncodedConfig> DeserializeAs<'de, OffsetDateTime> for Iso8601<CONFIG> {
614    fn deserialize_as<D>(deserializer: D) -> Result<OffsetDateTime, D::Error>
615    where
616        D: Deserializer<'de>,
617    {
618        struct Helper<const CONFIG: EncodedConfig>;
619        impl<const CONFIG: EncodedConfig> Visitor<'_> for Helper<CONFIG> {
620            type Value = OffsetDateTime;
621
622            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
623                formatter.write_str("a ISO8601-formatted `OffsetDateTime`")
624            }
625
626            fn visit_str<E: DeError>(self, value: &str) -> Result<Self::Value, E> {
627                Self::Value::parse(value, &Iso8601::<CONFIG>).map_err(E::custom)
628            }
629        }
630
631        deserializer.deserialize_str(Helper::<CONFIG>)
632    }
633}