Skip to main content

time/serde/
mod.rs

1//! Differential formats for serde.
2// This also includes the serde implementations for all types. This doesn't need to be externally
3// documented, though.
4
5// Types with guaranteed stable serde representations. Strings are avoided to allow for optimal
6// representations in various binary forms.
7
8/// Consume the next item in a sequence.
9macro_rules! item {
10    ($seq:expr, $name:literal) => {
11        $seq.next_element()?
12            .ok_or_else(|| <A::Error as serde_core::de::Error>::custom(concat!("expected ", $name)))
13    };
14}
15
16#[cfg(any(feature = "formatting", feature = "parsing"))]
17pub mod iso8601;
18#[cfg(any(feature = "formatting", feature = "parsing"))]
19pub mod rfc2822;
20#[cfg(any(feature = "formatting", feature = "parsing"))]
21pub mod rfc3339;
22pub mod timestamp;
23mod visitor;
24
25#[cfg(feature = "serde-human-readable")]
26use alloc::string::ToString;
27use core::marker::PhantomData;
28
29#[cfg(feature = "serde-human-readable")]
30use serde_core::ser::Error as _;
31use serde_core::{Deserialize, Deserializer, Serialize, Serializer};
32/// Generate a custom serializer and deserializer from a format string or an existing format.
33///
34/// The format description syntax accepted by this macro is the same as
35/// [`format_description::parse()`], which can be found in [the
36/// book][format-description-syntax].
37///
38/// [format-description-syntax]: https://time-rs.github.io/book/api/format-description.html
39///
40/// # Syntax
41///
42/// **It is recommended to use version 3.** For backwards compatibility, this macro defaults to
43/// version 1. To use version 2 or version 3, you can specify the version as the first
44/// argument: `serde::format_description!(version = 2, mod_name, Date, FORMAT)`.
45///
46/// For versions 1 and 2, this macro is invoked as `serde::format_description!(mod_name, Date,
47/// FORMAT)` where `FORMAT` is either a `"<format string>"` or something that implements
48#[cfg_attr(
49    all(feature = "formatting", feature = "parsing"),
50    doc = "[`Formattable`](crate::formatting::Formattable) and \
51           [`Parsable`](crate::parsing::Parsable)."
52)]
53#[cfg_attr(
54    all(feature = "formatting", not(feature = "parsing")),
55    doc = "[`Formattable`](crate::formatting::Formattable)."
56)]
57#[cfg_attr(
58    all(not(feature = "formatting"), feature = "parsing"),
59    doc = "[`Parsable`](crate::parsing::Parsable)."
60)]
61/// This puts a module named `mod_name` in the current scope that can be used to format `Date`
62/// structs. A submodule (`mod_name::option`) is also generated for `Option<Date>`. Both
63/// modules are only visible in the current scope by default. To increase visibility, you can
64/// specify `pub`, `pub(crate)`, or similar before the module name:
65/// `serde::format_description!(pub mod_name, Date, FORMAT)`.
66///
67/// For version 3, this macro is invoked as `serde::format_description!(mod mod_name [Date] =
68/// FORMAT)`. As with versions 1 and 2, visibility can be specified before the `mod` keyword.
69/// The type being formatted and/or parsed must be in scope, as the macro will not import it
70/// for you. Note: the `mod` keyword indicates that this is version 3 of the macro; specifying
71/// `version = 3` is accepted but unnecessary.
72///
73/// # Semantics
74///
75/// The returned `Option` will contain a deserialized value if present and `None` if the field
76/// is present but the value is `null` (or the equivalent in other formats). To return `None`
77/// when the field is not present, you should use `#[serde(default)]` on the field.
78///
79/// Note: Due to [serde-rs/serde#2878](https://github.com/serde-rs/serde#2878), you will need to
80/// apply `#[serde(default)]` if you want a missing field to deserialize as `None`.
81///
82/// # Examples
83///
84/// Using a format string:
85///
86/// ```rust,no_run
87/// # use time::OffsetDateTime;
88#[cfg_attr(
89    all(feature = "formatting", feature = "parsing"),
90    doc = "use ::serde::{Serialize, Deserialize};"
91)]
92#[cfg_attr(
93    all(feature = "formatting", not(feature = "parsing")),
94    doc = "use ::serde::Serialize;"
95)]
96#[cfg_attr(
97    all(not(feature = "formatting"), feature = "parsing"),
98    doc = "use ::serde::Deserialize;"
99)]
100/// use time::serde;
101///
102/// // Makes a module `mod my_format { ... }`.
103/// serde::format_description!(my_format, OffsetDateTime, "hour=[hour], minute=[minute]");
104///
105/// # #[allow(dead_code)]
106#[cfg_attr(
107    all(feature = "formatting", feature = "parsing"),
108    doc = "#[derive(Serialize, Deserialize)]"
109)]
110#[cfg_attr(
111    all(feature = "formatting", not(feature = "parsing")),
112    doc = "#[derive(Serialize)]"
113)]
114#[cfg_attr(
115    all(not(feature = "formatting"), feature = "parsing"),
116    doc = "#[derive(Deserialize)]"
117)]
118/// struct SerializesWithCustom {
119///     #[serde(with = "my_format")]
120///     dt: OffsetDateTime,
121///     #[serde(with = "my_format::option", default)]
122///     maybe_dt: Option<OffsetDateTime>,
123/// }
124/// ```
125/// 
126/// Define the format separately to be used in multiple places:
127/// ```rust,no_run
128/// # use time::OffsetDateTime;
129#[cfg_attr(
130    all(feature = "formatting", feature = "parsing"),
131    doc = "use ::serde::{Serialize, Deserialize};"
132)]
133#[cfg_attr(
134    all(feature = "formatting", not(feature = "parsing")),
135    doc = "use ::serde::Serialize;"
136)]
137#[cfg_attr(
138    all(not(feature = "formatting"), feature = "parsing"),
139    doc = "use ::serde::Deserialize;"
140)]
141/// use time::serde;
142/// use time::format_description::StaticFormatDescription;
143///
144/// const DATE_TIME_FORMAT: StaticFormatDescription = time::macros::format_description!(
145///     "hour=[hour], minute=[minute]"
146/// );
147///
148/// // Makes a module `mod my_format { ... }`.
149/// serde::format_description!(my_format, OffsetDateTime, DATE_TIME_FORMAT);
150///
151/// # #[allow(dead_code)]
152#[cfg_attr(
153    all(feature = "formatting", feature = "parsing"),
154    doc = "#[derive(Serialize, Deserialize)]"
155)]
156#[cfg_attr(
157    all(feature = "formatting", not(feature = "parsing")),
158    doc = "#[derive(Serialize)]"
159)]
160#[cfg_attr(
161    all(not(feature = "formatting"), feature = "parsing"),
162    doc = "#[derive(Deserialize)]"
163)]
164/// struct SerializesWithCustom {
165///     #[serde(with = "my_format")]
166///     dt: OffsetDateTime,
167///     #[serde(with = "my_format::option", default)]
168///     maybe_dt: Option<OffsetDateTime>,
169/// }
170///
171/// fn main() {
172///     # #[expect(unused_variables)]
173///     let str_ts = OffsetDateTime::now_utc().format(DATE_TIME_FORMAT).unwrap();
174/// }
175/// ```
176/// 
177/// Customize the configuration of ISO 8601 formatting/parsing:
178/// ```rust,no_run
179/// # use time::OffsetDateTime;
180#[cfg_attr(
181    all(feature = "formatting", feature = "parsing"),
182    doc = "use ::serde::{Serialize, Deserialize};"
183)]
184#[cfg_attr(
185    all(feature = "formatting", not(feature = "parsing")),
186    doc = "use ::serde::Serialize;"
187)]
188#[cfg_attr(
189    all(not(feature = "formatting"), feature = "parsing"),
190    doc = "use ::serde::Deserialize;"
191)]
192/// use time::serde;
193/// use time::format_description::well_known::{iso8601, Iso8601};
194///
195/// # #[allow(dead_code)]
196/// const CONFIG: iso8601::EncodedConfig = iso8601::Config::DEFAULT
197///     .set_year_is_six_digits(false)
198///     .encode();
199/// # #[allow(dead_code)]
200/// const FORMAT: Iso8601<CONFIG> = Iso8601::<CONFIG>;
201///
202/// // Makes a module `mod my_format { ... }`.
203/// serde::format_description!(my_format, OffsetDateTime, FORMAT);
204///
205/// # #[allow(dead_code)]
206#[cfg_attr(
207    all(feature = "formatting", feature = "parsing"),
208    doc = "#[derive(Serialize, Deserialize)]"
209)]
210#[cfg_attr(
211    all(feature = "formatting", not(feature = "parsing")),
212    doc = "#[derive(Serialize)]"
213)]
214#[cfg_attr(
215    all(not(feature = "formatting"), feature = "parsing"),
216    doc = "#[derive(Deserialize)]"
217)]
218/// struct SerializesWithCustom {
219///     #[serde(with = "my_format")]
220///     dt: OffsetDateTime,
221///     #[serde(with = "my_format::option", default)]
222///     maybe_dt: Option<OffsetDateTime>,
223/// }
224/// # fn main() {}
225/// ```
226/// 
227/// [`format_description::parse()`]: crate::format_description::parse()
228#[cfg(all(feature = "macros", any(feature = "formatting", feature = "parsing")))]
229pub use time_macros::serde_format_description as format_description;
230
231use self::visitor::Visitor;
232#[cfg(feature = "parsing")]
233use crate::format_description::__private::FormatDescriptionV3Inner;
234#[cfg(feature = "parsing")]
235use crate::format_description::{FormatDescriptionV3, modifier};
236use crate::{
237    Date, Duration, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcDateTime, UtcOffset, Weekday,
238};
239
240/// The format used when serializing and deserializing a human-readable `Date`.
241#[cfg(feature = "parsing")]
242const DATE_FORMAT: FormatDescriptionV3<'_> = FormatDescriptionV3Inner::BorrowedCompound(&[
243    #[cfg(feature = "large-dates")]
244    FormatDescriptionV3Inner::CalendarYearFullExtendedRange(
245        modifier::CalendarYearFullExtendedRange::default(),
246    ),
247    #[cfg(not(feature = "large-dates"))]
248    FormatDescriptionV3Inner::CalendarYearFullStandardRange(
249        modifier::CalendarYearFullStandardRange::default(),
250    ),
251    FormatDescriptionV3Inner::BorrowedLiteral("-"),
252    FormatDescriptionV3Inner::MonthNumerical(modifier::MonthNumerical::default()),
253    FormatDescriptionV3Inner::BorrowedLiteral("-"),
254    FormatDescriptionV3Inner::Day(modifier::Day::default()),
255])
256.into_opaque();
257
258impl Serialize for Date {
259    #[inline]
260    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
261    where
262        S: Serializer,
263    {
264        #[cfg(feature = "serde-human-readable")]
265        if serializer.is_human_readable() {
266            let Ok(s) = self.format(&DATE_FORMAT) else {
267                return Err(S::Error::custom("failed formatting `Date`"));
268            };
269            return serializer.serialize_str(&s);
270        }
271
272        (self.year(), self.ordinal()).serialize(serializer)
273    }
274}
275
276impl<'a> Deserialize<'a> for Date {
277    #[inline]
278    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
279    where
280        D: Deserializer<'a>,
281    {
282        if cfg!(feature = "serde-human-readable") && deserializer.is_human_readable() {
283            deserializer.deserialize_any(Visitor::<Self>(PhantomData))
284        } else {
285            deserializer.deserialize_tuple(2, Visitor::<Self>(PhantomData))
286        }
287    }
288}
289
290impl Serialize for Duration {
291    #[inline]
292    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
293    where
294        S: Serializer,
295    {
296        #[cfg(feature = "serde-human-readable")]
297        if serializer.is_human_readable() {
298            return serializer.collect_str(&format_args!(
299                "{}{}.{:>09}",
300                if self.is_negative() { "-" } else { "" },
301                self.whole_seconds().unsigned_abs(),
302                self.subsec_nanoseconds().abs(),
303            ));
304        }
305
306        (self.whole_seconds(), self.subsec_nanoseconds()).serialize(serializer)
307    }
308}
309
310impl<'a> Deserialize<'a> for Duration {
311    #[inline]
312    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
313    where
314        D: Deserializer<'a>,
315    {
316        if cfg!(feature = "serde-human-readable") && deserializer.is_human_readable() {
317            deserializer.deserialize_any(Visitor::<Self>(PhantomData))
318        } else {
319            deserializer.deserialize_tuple(2, Visitor::<Self>(PhantomData))
320        }
321    }
322}
323
324/// The format used when serializing and deserializing a human-readable `OffsetDateTime`.
325#[cfg(feature = "parsing")]
326const OFFSET_DATE_TIME_FORMAT: FormatDescriptionV3<'_> =
327    FormatDescriptionV3Inner::BorrowedCompound(&[
328        #[cfg(feature = "large-dates")]
329        FormatDescriptionV3Inner::CalendarYearFullExtendedRange(
330            modifier::CalendarYearFullExtendedRange::default(),
331        ),
332        #[cfg(not(feature = "large-dates"))]
333        FormatDescriptionV3Inner::CalendarYearFullStandardRange(
334            modifier::CalendarYearFullStandardRange::default(),
335        ),
336        FormatDescriptionV3Inner::BorrowedLiteral("-"),
337        FormatDescriptionV3Inner::MonthNumerical(modifier::MonthNumerical::default()),
338        FormatDescriptionV3Inner::BorrowedLiteral("-"),
339        FormatDescriptionV3Inner::Day(modifier::Day::default()),
340        FormatDescriptionV3Inner::BorrowedLiteral(" "),
341        FormatDescriptionV3Inner::Hour24(modifier::Hour24::default()),
342        FormatDescriptionV3Inner::BorrowedLiteral(":"),
343        FormatDescriptionV3Inner::Minute(modifier::Minute::default()),
344        FormatDescriptionV3Inner::BorrowedLiteral(":"),
345        FormatDescriptionV3Inner::Second(modifier::Second::default()),
346        FormatDescriptionV3Inner::BorrowedLiteral("."),
347        FormatDescriptionV3Inner::Subsecond(modifier::Subsecond::default()),
348        FormatDescriptionV3Inner::BorrowedLiteral(" "),
349        FormatDescriptionV3Inner::OffsetHour(
350            modifier::OffsetHour::default().with_sign_is_mandatory(true),
351        ),
352        FormatDescriptionV3Inner::BorrowedLiteral(":"),
353        FormatDescriptionV3Inner::OffsetMinute(modifier::OffsetMinute::default()),
354        FormatDescriptionV3Inner::BorrowedLiteral(":"),
355        FormatDescriptionV3Inner::OffsetSecond(modifier::OffsetSecond::default()),
356    ])
357    .into_opaque();
358
359impl Serialize for OffsetDateTime {
360    #[inline]
361    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
362    where
363        S: Serializer,
364    {
365        #[cfg(feature = "serde-human-readable")]
366        if serializer.is_human_readable() {
367            let Ok(s) = self.format(&OFFSET_DATE_TIME_FORMAT) else {
368                return Err(S::Error::custom("failed formatting `OffsetDateTime`"));
369            };
370            return serializer.serialize_str(&s);
371        }
372
373        (
374            self.year(),
375            self.ordinal(),
376            self.hour(),
377            self.minute(),
378            self.second(),
379            self.nanosecond(),
380            self.offset().whole_hours(),
381            self.offset().minutes_past_hour(),
382            self.offset().seconds_past_minute(),
383        )
384            .serialize(serializer)
385    }
386}
387
388impl<'a> Deserialize<'a> for OffsetDateTime {
389    #[inline]
390    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
391    where
392        D: Deserializer<'a>,
393    {
394        if cfg!(feature = "serde-human-readable") && deserializer.is_human_readable() {
395            deserializer.deserialize_any(Visitor::<Self>(PhantomData))
396        } else {
397            deserializer.deserialize_tuple(9, Visitor::<Self>(PhantomData))
398        }
399    }
400}
401
402/// The format used when serializing and deserializing a human-readable `PrimitiveDateTime`.
403#[cfg(feature = "parsing")]
404const PRIMITIVE_DATE_TIME_FORMAT: FormatDescriptionV3<'_> =
405    FormatDescriptionV3Inner::BorrowedCompound(&[
406        #[cfg(feature = "large-dates")]
407        FormatDescriptionV3Inner::CalendarYearFullExtendedRange(
408            modifier::CalendarYearFullExtendedRange::default(),
409        ),
410        #[cfg(not(feature = "large-dates"))]
411        FormatDescriptionV3Inner::CalendarYearFullStandardRange(
412            modifier::CalendarYearFullStandardRange::default(),
413        ),
414        FormatDescriptionV3Inner::BorrowedLiteral("-"),
415        FormatDescriptionV3Inner::MonthNumerical(modifier::MonthNumerical::default()),
416        FormatDescriptionV3Inner::BorrowedLiteral("-"),
417        FormatDescriptionV3Inner::Day(modifier::Day::default()),
418        FormatDescriptionV3Inner::BorrowedLiteral(" "),
419        FormatDescriptionV3Inner::Hour24(modifier::Hour24::default()),
420        FormatDescriptionV3Inner::BorrowedLiteral(":"),
421        FormatDescriptionV3Inner::Minute(modifier::Minute::default()),
422        FormatDescriptionV3Inner::BorrowedLiteral(":"),
423        FormatDescriptionV3Inner::Second(modifier::Second::default()),
424        FormatDescriptionV3Inner::BorrowedLiteral("."),
425        FormatDescriptionV3Inner::Subsecond(modifier::Subsecond::default()),
426    ])
427    .into_opaque();
428
429impl Serialize for PrimitiveDateTime {
430    #[inline]
431    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
432    where
433        S: Serializer,
434    {
435        #[cfg(feature = "serde-human-readable")]
436        if serializer.is_human_readable() {
437            let Ok(s) = self.format(&PRIMITIVE_DATE_TIME_FORMAT) else {
438                return Err(S::Error::custom("failed formatting `PrimitiveDateTime`"));
439            };
440            return serializer.serialize_str(&s);
441        }
442
443        (
444            self.year(),
445            self.ordinal(),
446            self.hour(),
447            self.minute(),
448            self.second(),
449            self.nanosecond(),
450        )
451            .serialize(serializer)
452    }
453}
454
455impl<'a> Deserialize<'a> for PrimitiveDateTime {
456    #[inline]
457    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
458    where
459        D: Deserializer<'a>,
460    {
461        if cfg!(feature = "serde-human-readable") && deserializer.is_human_readable() {
462            deserializer.deserialize_any(Visitor::<Self>(PhantomData))
463        } else {
464            deserializer.deserialize_tuple(6, Visitor::<Self>(PhantomData))
465        }
466    }
467}
468
469/// The format used when serializing and deserializing a human-readable `UtcDateTime`.
470#[cfg(feature = "parsing")]
471const UTC_DATE_TIME_FORMAT: FormatDescriptionV3<'_> = PRIMITIVE_DATE_TIME_FORMAT;
472
473impl Serialize for UtcDateTime {
474    #[inline]
475    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
476    where
477        S: Serializer,
478    {
479        #[cfg(feature = "serde-human-readable")]
480        if serializer.is_human_readable() {
481            let Ok(s) = self.format(&PRIMITIVE_DATE_TIME_FORMAT) else {
482                return Err(S::Error::custom("failed formatting `UtcDateTime`"));
483            };
484            return serializer.serialize_str(&s);
485        }
486
487        (
488            self.year(),
489            self.ordinal(),
490            self.hour(),
491            self.minute(),
492            self.second(),
493            self.nanosecond(),
494        )
495            .serialize(serializer)
496    }
497}
498
499impl<'a> Deserialize<'a> for UtcDateTime {
500    #[inline]
501    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
502    where
503        D: Deserializer<'a>,
504    {
505        if cfg!(feature = "serde-human-readable") && deserializer.is_human_readable() {
506            deserializer.deserialize_any(Visitor::<Self>(PhantomData))
507        } else {
508            deserializer.deserialize_tuple(6, Visitor::<Self>(PhantomData))
509        }
510    }
511}
512
513/// The format used when serializing and deserializing a human-readable `Time`.
514#[cfg(feature = "parsing")]
515const TIME_FORMAT: FormatDescriptionV3<'_> = FormatDescriptionV3Inner::BorrowedCompound(&[
516    FormatDescriptionV3Inner::Hour24(modifier::Hour24::default()),
517    FormatDescriptionV3Inner::BorrowedLiteral(":"),
518    FormatDescriptionV3Inner::Minute(modifier::Minute::default()),
519    FormatDescriptionV3Inner::BorrowedLiteral(":"),
520    FormatDescriptionV3Inner::Second(modifier::Second::default()),
521    FormatDescriptionV3Inner::BorrowedLiteral("."),
522    FormatDescriptionV3Inner::Subsecond(modifier::Subsecond::default()),
523])
524.into_opaque();
525
526impl Serialize for Time {
527    #[inline]
528    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
529    where
530        S: Serializer,
531    {
532        #[cfg(feature = "serde-human-readable")]
533        if serializer.is_human_readable() {
534            let Ok(s) = self.format(&TIME_FORMAT) else {
535                return Err(S::Error::custom("failed formatting `Time`"));
536            };
537            return serializer.serialize_str(&s);
538        }
539
540        (self.hour(), self.minute(), self.second(), self.nanosecond()).serialize(serializer)
541    }
542}
543
544impl<'a> Deserialize<'a> for Time {
545    #[inline]
546    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
547    where
548        D: Deserializer<'a>,
549    {
550        if cfg!(feature = "serde-human-readable") && deserializer.is_human_readable() {
551            deserializer.deserialize_any(Visitor::<Self>(PhantomData))
552        } else {
553            deserializer.deserialize_tuple(4, Visitor::<Self>(PhantomData))
554        }
555    }
556}
557
558/// The format used when serializing and deserializing a human-readable `UtcOffset`.
559#[cfg(feature = "parsing")]
560const UTC_OFFSET_FORMAT: FormatDescriptionV3<'_> = FormatDescriptionV3Inner::BorrowedCompound(&[
561    FormatDescriptionV3Inner::OffsetHour(
562        modifier::OffsetHour::default().with_sign_is_mandatory(true),
563    ),
564    FormatDescriptionV3Inner::BorrowedLiteral(":"),
565    FormatDescriptionV3Inner::OffsetMinute(modifier::OffsetMinute::default()),
566    FormatDescriptionV3Inner::BorrowedLiteral(":"),
567    FormatDescriptionV3Inner::OffsetSecond(modifier::OffsetSecond::default()),
568])
569.into_opaque();
570
571impl Serialize for UtcOffset {
572    #[inline]
573    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
574    where
575        S: Serializer,
576    {
577        #[cfg(feature = "serde-human-readable")]
578        if serializer.is_human_readable() {
579            let Ok(s) = self.format(&UTC_OFFSET_FORMAT) else {
580                return Err(S::Error::custom("failed formatting `UtcOffset`"));
581            };
582            return serializer.serialize_str(&s);
583        }
584
585        (
586            self.whole_hours(),
587            self.minutes_past_hour(),
588            self.seconds_past_minute(),
589        )
590            .serialize(serializer)
591    }
592}
593
594impl<'a> Deserialize<'a> for UtcOffset {
595    #[inline]
596    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
597    where
598        D: Deserializer<'a>,
599    {
600        if cfg!(feature = "serde-human-readable") && deserializer.is_human_readable() {
601            deserializer.deserialize_any(Visitor::<Self>(PhantomData))
602        } else {
603            deserializer.deserialize_tuple(3, Visitor::<Self>(PhantomData))
604        }
605    }
606}
607
608impl Serialize for Weekday {
609    #[inline]
610    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
611    where
612        S: Serializer,
613    {
614        #[cfg(feature = "serde-human-readable")]
615        if serializer.is_human_readable() {
616            #[cfg(not(feature = "std"))]
617            use alloc::string::ToString;
618            return self.to_string().serialize(serializer);
619        }
620
621        self.number_from_monday().serialize(serializer)
622    }
623}
624
625impl<'a> Deserialize<'a> for Weekday {
626    #[inline]
627    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
628    where
629        D: Deserializer<'a>,
630    {
631        if cfg!(feature = "serde-human-readable") && deserializer.is_human_readable() {
632            deserializer.deserialize_any(Visitor::<Self>(PhantomData))
633        } else {
634            deserializer.deserialize_u8(Visitor::<Self>(PhantomData))
635        }
636    }
637}
638
639impl Serialize for Month {
640    #[inline]
641    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
642    where
643        S: Serializer,
644    {
645        #[cfg(feature = "serde-human-readable")]
646        if serializer.is_human_readable() {
647            #[cfg(not(feature = "std"))]
648            use alloc::string::String;
649            return self.to_string().serialize(serializer);
650        }
651
652        u8::from(*self).serialize(serializer)
653    }
654}
655
656impl<'a> Deserialize<'a> for Month {
657    #[inline]
658    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
659    where
660        D: Deserializer<'a>,
661    {
662        if cfg!(feature = "serde-human-readable") && deserializer.is_human_readable() {
663            deserializer.deserialize_any(Visitor::<Self>(PhantomData))
664        } else {
665            deserializer.deserialize_u8(Visitor::<Self>(PhantomData))
666        }
667    }
668}