1macro_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#[cfg_attr(
42 all(feature = "formatting", feature = "parsing"),
43 doc = "[`Formattable`](crate::formatting::Formattable) and \
44 [`Parsable`](crate::parsing::Parsable)."
45)]
46#[cfg_attr(
47 all(feature = "formatting", not(feature = "parsing")),
48 doc = "[`Formattable`](crate::formatting::Formattable)."
49)]
50#[cfg_attr(
51 all(not(feature = "formatting"), feature = "parsing"),
52 doc = "[`Parsable`](crate::parsing::Parsable)."
53)]
54#[cfg_attr(
74 all(feature = "formatting", feature = "parsing"),
75 doc = "use ::serde::{Serialize, Deserialize};"
76)]
77#[cfg_attr(
78 all(feature = "formatting", not(feature = "parsing")),
79 doc = "use ::serde::Serialize;"
80)]
81#[cfg_attr(
82 all(not(feature = "formatting"), feature = "parsing"),
83 doc = "use ::serde::Deserialize;"
84)]
85#[cfg_attr(
92 all(feature = "formatting", feature = "parsing"),
93 doc = "#[derive(Serialize, Deserialize)]"
94)]
95#[cfg_attr(
96 all(feature = "formatting", not(feature = "parsing")),
97 doc = "#[derive(Serialize)]"
98)]
99#[cfg_attr(
100 all(not(feature = "formatting"), feature = "parsing"),
101 doc = "#[derive(Deserialize)]"
102)]
103#[cfg_attr(
115 all(feature = "formatting", feature = "parsing"),
116 doc = "use ::serde::{Serialize, Deserialize};"
117)]
118#[cfg_attr(
119 all(feature = "formatting", not(feature = "parsing")),
120 doc = "use ::serde::Serialize;"
121)]
122#[cfg_attr(
123 all(not(feature = "formatting"), feature = "parsing"),
124 doc = "use ::serde::Deserialize;"
125)]
126#[cfg_attr(
138 all(feature = "formatting", feature = "parsing"),
139 doc = "#[derive(Serialize, Deserialize)]"
140)]
141#[cfg_attr(
142 all(feature = "formatting", not(feature = "parsing")),
143 doc = "#[derive(Serialize)]"
144)]
145#[cfg_attr(
146 all(not(feature = "formatting"), feature = "parsing"),
147 doc = "#[derive(Deserialize)]"
148)]
149#[cfg_attr(
166 all(feature = "formatting", feature = "parsing"),
167 doc = "use ::serde::{Serialize, Deserialize};"
168)]
169#[cfg_attr(
170 all(feature = "formatting", not(feature = "parsing")),
171 doc = "use ::serde::Serialize;"
172)]
173#[cfg_attr(
174 all(not(feature = "formatting"), feature = "parsing"),
175 doc = "use ::serde::Deserialize;"
176)]
177#[cfg_attr(
192 all(feature = "formatting", feature = "parsing"),
193 doc = "#[derive(Serialize, Deserialize)]"
194)]
195#[cfg_attr(
196 all(feature = "formatting", not(feature = "parsing")),
197 doc = "#[derive(Serialize)]"
198)]
199#[cfg_attr(
200 all(not(feature = "formatting"), feature = "parsing"),
201 doc = "#[derive(Deserialize)]"
202)]
203#[cfg(all(feature = "macros", any(feature = "formatting", feature = "parsing")))]
214pub use time_macros::serde_format_description as format_description;
215
216use self::visitor::Visitor;
217#[cfg(feature = "parsing")]
218use crate::format_description::{BorrowedFormatItem, Component, StaticFormatDescription, modifier};
219use crate::{
220 Date, Duration, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcDateTime, UtcOffset, Weekday,
221};
222
223#[cfg(feature = "parsing")]
225const DATE_FORMAT: StaticFormatDescription = &[
226 BorrowedFormatItem::Component(Component::Year(modifier::Year::default())),
227 BorrowedFormatItem::Literal(b"-"),
228 BorrowedFormatItem::Component(Component::Month(modifier::Month::default())),
229 BorrowedFormatItem::Literal(b"-"),
230 BorrowedFormatItem::Component(Component::Day(modifier::Day::default())),
231];
232
233impl Serialize for Date {
234 #[inline]
235 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
236 where
237 S: Serializer,
238 {
239 #[cfg(feature = "serde-human-readable")]
240 if serializer.is_human_readable() {
241 let Ok(s) = self.format(&DATE_FORMAT) else {
242 return Err(S::Error::custom("failed formatting `Date`"));
243 };
244 return serializer.serialize_str(&s);
245 }
246
247 (self.year(), self.ordinal()).serialize(serializer)
248 }
249}
250
251impl<'a> Deserialize<'a> for Date {
252 #[inline]
253 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
254 where
255 D: Deserializer<'a>,
256 {
257 if cfg!(feature = "serde-human-readable") && deserializer.is_human_readable() {
258 deserializer.deserialize_any(Visitor::<Self>(PhantomData))
259 } else {
260 deserializer.deserialize_tuple(2, Visitor::<Self>(PhantomData))
261 }
262 }
263}
264
265impl Serialize for Duration {
266 #[inline]
267 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
268 where
269 S: Serializer,
270 {
271 #[cfg(feature = "serde-human-readable")]
272 if serializer.is_human_readable() {
273 return serializer.collect_str(&format_args!(
274 "{}{}.{:>09}",
275 if self.is_negative() { "-" } else { "" },
276 self.whole_seconds().unsigned_abs(),
277 self.subsec_nanoseconds().abs(),
278 ));
279 }
280
281 (self.whole_seconds(), self.subsec_nanoseconds()).serialize(serializer)
282 }
283}
284
285impl<'a> Deserialize<'a> for Duration {
286 #[inline]
287 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
288 where
289 D: Deserializer<'a>,
290 {
291 if cfg!(feature = "serde-human-readable") && deserializer.is_human_readable() {
292 deserializer.deserialize_any(Visitor::<Self>(PhantomData))
293 } else {
294 deserializer.deserialize_tuple(2, Visitor::<Self>(PhantomData))
295 }
296 }
297}
298
299#[cfg(feature = "parsing")]
301const OFFSET_DATE_TIME_FORMAT: StaticFormatDescription = &[
302 BorrowedFormatItem::Compound(DATE_FORMAT),
303 BorrowedFormatItem::Literal(b" "),
304 BorrowedFormatItem::Compound(TIME_FORMAT),
305 BorrowedFormatItem::Literal(b" "),
306 BorrowedFormatItem::Compound(UTC_OFFSET_FORMAT),
307];
308
309impl Serialize for OffsetDateTime {
310 #[inline]
311 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
312 where
313 S: Serializer,
314 {
315 #[cfg(feature = "serde-human-readable")]
316 if serializer.is_human_readable() {
317 let Ok(s) = self.format(&OFFSET_DATE_TIME_FORMAT) else {
318 return Err(S::Error::custom("failed formatting `OffsetDateTime`"));
319 };
320 return serializer.serialize_str(&s);
321 }
322
323 (
324 self.year(),
325 self.ordinal(),
326 self.hour(),
327 self.minute(),
328 self.second(),
329 self.nanosecond(),
330 self.offset().whole_hours(),
331 self.offset().minutes_past_hour(),
332 self.offset().seconds_past_minute(),
333 )
334 .serialize(serializer)
335 }
336}
337
338impl<'a> Deserialize<'a> for OffsetDateTime {
339 #[inline]
340 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
341 where
342 D: Deserializer<'a>,
343 {
344 if cfg!(feature = "serde-human-readable") && deserializer.is_human_readable() {
345 deserializer.deserialize_any(Visitor::<Self>(PhantomData))
346 } else {
347 deserializer.deserialize_tuple(9, Visitor::<Self>(PhantomData))
348 }
349 }
350}
351
352#[cfg(feature = "parsing")]
354const PRIMITIVE_DATE_TIME_FORMAT: StaticFormatDescription = &[
355 BorrowedFormatItem::Compound(DATE_FORMAT),
356 BorrowedFormatItem::Literal(b" "),
357 BorrowedFormatItem::Compound(TIME_FORMAT),
358];
359
360impl Serialize for PrimitiveDateTime {
361 #[inline]
362 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
363 where
364 S: Serializer,
365 {
366 #[cfg(feature = "serde-human-readable")]
367 if serializer.is_human_readable() {
368 let Ok(s) = self.format(&PRIMITIVE_DATE_TIME_FORMAT) else {
369 return Err(S::Error::custom("failed formatting `PrimitiveDateTime`"));
370 };
371 return serializer.serialize_str(&s);
372 }
373
374 (
375 self.year(),
376 self.ordinal(),
377 self.hour(),
378 self.minute(),
379 self.second(),
380 self.nanosecond(),
381 )
382 .serialize(serializer)
383 }
384}
385
386impl<'a> Deserialize<'a> for PrimitiveDateTime {
387 #[inline]
388 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
389 where
390 D: Deserializer<'a>,
391 {
392 if cfg!(feature = "serde-human-readable") && deserializer.is_human_readable() {
393 deserializer.deserialize_any(Visitor::<Self>(PhantomData))
394 } else {
395 deserializer.deserialize_tuple(6, Visitor::<Self>(PhantomData))
396 }
397 }
398}
399
400#[cfg(feature = "parsing")]
402const UTC_DATE_TIME_FORMAT: StaticFormatDescription = PRIMITIVE_DATE_TIME_FORMAT;
403
404impl Serialize for UtcDateTime {
405 #[inline]
406 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
407 where
408 S: Serializer,
409 {
410 #[cfg(feature = "serde-human-readable")]
411 if serializer.is_human_readable() {
412 let Ok(s) = self.format(&PRIMITIVE_DATE_TIME_FORMAT) else {
413 return Err(S::Error::custom("failed formatting `UtcDateTime`"));
414 };
415 return serializer.serialize_str(&s);
416 }
417
418 (
419 self.year(),
420 self.ordinal(),
421 self.hour(),
422 self.minute(),
423 self.second(),
424 self.nanosecond(),
425 )
426 .serialize(serializer)
427 }
428}
429
430impl<'a> Deserialize<'a> for UtcDateTime {
431 #[inline]
432 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
433 where
434 D: Deserializer<'a>,
435 {
436 if cfg!(feature = "serde-human-readable") && deserializer.is_human_readable() {
437 deserializer.deserialize_any(Visitor::<Self>(PhantomData))
438 } else {
439 deserializer.deserialize_tuple(6, Visitor::<Self>(PhantomData))
440 }
441 }
442}
443
444#[cfg(feature = "parsing")]
446const TIME_FORMAT: StaticFormatDescription = &[
447 BorrowedFormatItem::Component(Component::Hour(modifier::Hour::default())),
448 BorrowedFormatItem::Literal(b":"),
449 BorrowedFormatItem::Component(Component::Minute(modifier::Minute::default())),
450 BorrowedFormatItem::Literal(b":"),
451 BorrowedFormatItem::Component(Component::Second(modifier::Second::default())),
452 BorrowedFormatItem::Literal(b"."),
453 BorrowedFormatItem::Component(Component::Subsecond(modifier::Subsecond::default())),
454];
455
456impl Serialize for Time {
457 #[inline]
458 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
459 where
460 S: Serializer,
461 {
462 #[cfg(feature = "serde-human-readable")]
463 if serializer.is_human_readable() {
464 let Ok(s) = self.format(&TIME_FORMAT) else {
465 return Err(S::Error::custom("failed formatting `Time`"));
466 };
467 return serializer.serialize_str(&s);
468 }
469
470 (self.hour(), self.minute(), self.second(), self.nanosecond()).serialize(serializer)
471 }
472}
473
474impl<'a> Deserialize<'a> for Time {
475 #[inline]
476 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
477 where
478 D: Deserializer<'a>,
479 {
480 if cfg!(feature = "serde-human-readable") && deserializer.is_human_readable() {
481 deserializer.deserialize_any(Visitor::<Self>(PhantomData))
482 } else {
483 deserializer.deserialize_tuple(4, Visitor::<Self>(PhantomData))
484 }
485 }
486}
487
488#[cfg(feature = "parsing")]
490const UTC_OFFSET_FORMAT: StaticFormatDescription = &[
491 BorrowedFormatItem::Component(Component::OffsetHour(
492 const {
493 let mut m = modifier::OffsetHour::default();
494 m.sign_is_mandatory = true;
495 m
496 },
497 )),
498 BorrowedFormatItem::Optional(&BorrowedFormatItem::Compound(&[
499 BorrowedFormatItem::Literal(b":"),
500 BorrowedFormatItem::Component(Component::OffsetMinute(
501 const { modifier::OffsetMinute::default() },
502 )),
503 BorrowedFormatItem::Optional(&BorrowedFormatItem::Compound(&[
504 BorrowedFormatItem::Literal(b":"),
505 BorrowedFormatItem::Component(Component::OffsetSecond(
506 const { modifier::OffsetSecond::default() },
507 )),
508 ])),
509 ])),
510];
511
512impl Serialize for UtcOffset {
513 #[inline]
514 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
515 where
516 S: Serializer,
517 {
518 #[cfg(feature = "serde-human-readable")]
519 if serializer.is_human_readable() {
520 let Ok(s) = self.format(&UTC_OFFSET_FORMAT) else {
521 return Err(S::Error::custom("failed formatting `UtcOffset`"));
522 };
523 return serializer.serialize_str(&s);
524 }
525
526 (
527 self.whole_hours(),
528 self.minutes_past_hour(),
529 self.seconds_past_minute(),
530 )
531 .serialize(serializer)
532 }
533}
534
535impl<'a> Deserialize<'a> for UtcOffset {
536 #[inline]
537 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
538 where
539 D: Deserializer<'a>,
540 {
541 if cfg!(feature = "serde-human-readable") && deserializer.is_human_readable() {
542 deserializer.deserialize_any(Visitor::<Self>(PhantomData))
543 } else {
544 deserializer.deserialize_tuple(3, Visitor::<Self>(PhantomData))
545 }
546 }
547}
548
549impl Serialize for Weekday {
550 #[inline]
551 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
552 where
553 S: Serializer,
554 {
555 #[cfg(feature = "serde-human-readable")]
556 if serializer.is_human_readable() {
557 #[cfg(not(feature = "std"))]
558 use alloc::string::ToString;
559 return self.to_string().serialize(serializer);
560 }
561
562 self.number_from_monday().serialize(serializer)
563 }
564}
565
566impl<'a> Deserialize<'a> for Weekday {
567 #[inline]
568 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
569 where
570 D: Deserializer<'a>,
571 {
572 if cfg!(feature = "serde-human-readable") && deserializer.is_human_readable() {
573 deserializer.deserialize_any(Visitor::<Self>(PhantomData))
574 } else {
575 deserializer.deserialize_u8(Visitor::<Self>(PhantomData))
576 }
577 }
578}
579
580impl Serialize for Month {
581 #[inline]
582 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
583 where
584 S: Serializer,
585 {
586 #[cfg(feature = "serde-human-readable")]
587 if serializer.is_human_readable() {
588 #[cfg(not(feature = "std"))]
589 use alloc::string::String;
590 return self.to_string().serialize(serializer);
591 }
592
593 u8::from(*self).serialize(serializer)
594 }
595}
596
597impl<'a> Deserialize<'a> for Month {
598 #[inline]
599 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
600 where
601 D: Deserializer<'a>,
602 {
603 if cfg!(feature = "serde-human-readable") && deserializer.is_human_readable() {
604 deserializer.deserialize_any(Visitor::<Self>(PhantomData))
605 } else {
606 deserializer.deserialize_u8(Visitor::<Self>(PhantomData))
607 }
608 }
609}