1use core::num::{NonZeroU16, NonZeroU8};
4
5use deranged::{
6 OptionRangedI128, OptionRangedI32, OptionRangedI8, OptionRangedU16, OptionRangedU32,
7 OptionRangedU8, RangedI128, RangedI32, RangedI8, RangedU16, RangedU32, RangedU8,
8};
9use num_conv::prelude::*;
10
11use crate::convert::{Day, Hour, Minute, Nanosecond, Second};
12use crate::date::{MAX_YEAR, MIN_YEAR};
13use crate::error::TryFromParsed::InsufficientInformation;
14#[cfg(feature = "alloc")]
15use crate::format_description::OwnedFormatItem;
16use crate::format_description::{modifier, BorrowedFormatItem, Component};
17use crate::internal_macros::{bug, const_try_opt};
18use crate::parsing::component::{
19 parse_day, parse_end, parse_hour, parse_ignore, parse_minute, parse_month, parse_offset_hour,
20 parse_offset_minute, parse_offset_second, parse_ordinal, parse_period, parse_second,
21 parse_subsecond, parse_unix_timestamp, parse_week_number, parse_weekday, parse_year, Period,
22};
23use crate::parsing::ParsedItem;
24use crate::{error, Date, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcOffset, Weekday};
25
26mod sealed {
28 use super::*;
29
30 pub trait AnyFormatItem {
32 fn parse_item<'a>(
34 &self,
35 parsed: &mut Parsed,
36 input: &'a [u8],
37 ) -> Result<&'a [u8], error::ParseFromDescription>;
38 }
39}
40
41impl sealed::AnyFormatItem for BorrowedFormatItem<'_> {
42 fn parse_item<'a>(
43 &self,
44 parsed: &mut Parsed,
45 input: &'a [u8],
46 ) -> Result<&'a [u8], error::ParseFromDescription> {
47 match self {
48 Self::Literal(literal) => Parsed::parse_literal(input, literal),
49 Self::Component(component) => parsed.parse_component(input, *component),
50 Self::Compound(compound) => parsed.parse_items(input, compound),
51 Self::Optional(item) => parsed.parse_item(input, *item).or(Ok(input)),
52 Self::First(items) => {
53 let mut first_err = None;
54
55 for item in items.iter() {
56 match parsed.parse_item(input, item) {
57 Ok(remaining_input) => return Ok(remaining_input),
58 Err(err) if first_err.is_none() => first_err = Some(err),
59 Err(_) => {}
60 }
61 }
62
63 match first_err {
64 Some(err) => Err(err),
65 None => Ok(input),
68 }
69 }
70 }
71 }
72}
73
74#[cfg(feature = "alloc")]
75impl sealed::AnyFormatItem for OwnedFormatItem {
76 fn parse_item<'a>(
77 &self,
78 parsed: &mut Parsed,
79 input: &'a [u8],
80 ) -> Result<&'a [u8], error::ParseFromDescription> {
81 match self {
82 Self::Literal(literal) => Parsed::parse_literal(input, literal),
83 Self::Component(component) => parsed.parse_component(input, *component),
84 Self::Compound(compound) => parsed.parse_items(input, compound),
85 Self::Optional(item) => parsed.parse_item(input, item.as_ref()).or(Ok(input)),
86 Self::First(items) => {
87 let mut first_err = None;
88
89 for item in items.iter() {
90 match parsed.parse_item(input, item) {
91 Ok(remaining_input) => return Ok(remaining_input),
92 Err(err) if first_err.is_none() => first_err = Some(err),
93 Err(_) => {}
94 }
95 }
96
97 match first_err {
98 Some(err) => Err(err),
99 None => Ok(input),
102 }
103 }
104 }
105 }
106}
107
108#[derive(Debug, Clone, Copy)]
115pub struct Parsed {
116 year: OptionRangedI32<{ MIN_YEAR }, { MAX_YEAR }>,
118 year_last_two: OptionRangedU8<0, 99>,
120 iso_year: OptionRangedI32<{ MIN_YEAR }, { MAX_YEAR }>,
122 iso_year_last_two: OptionRangedU8<0, 99>,
124 month: Option<Month>,
126 sunday_week_number: OptionRangedU8<0, 53>,
128 monday_week_number: OptionRangedU8<0, 53>,
130 iso_week_number: OptionRangedU8<1, 53>,
132 weekday: Option<Weekday>,
134 ordinal: OptionRangedU16<1, 366>,
136 day: OptionRangedU8<1, 31>,
138 hour_24: OptionRangedU8<0, { Hour::per(Day) - 1 }>,
140 hour_12: OptionRangedU8<1, 12>,
143 hour_12_is_pm: Option<bool>,
145 minute: OptionRangedU8<0, { Minute::per(Hour) - 1 }>,
148 second: OptionRangedU8<0, { Second::per(Minute) }>,
151 subsecond: OptionRangedU32<0, { Nanosecond::per(Second) - 1 }>,
153 offset_hour: OptionRangedI8<-23, 23>,
155 offset_minute:
157 OptionRangedI8<{ -((Minute::per(Hour) - 1) as i8) }, { (Minute::per(Hour) - 1) as _ }>,
158 offset_second:
160 OptionRangedI8<{ -((Second::per(Minute) - 1) as i8) }, { (Second::per(Minute) - 1) as _ }>,
161 unix_timestamp_nanos: OptionRangedI128<
163 {
164 OffsetDateTime::new_in_offset(Date::MIN, Time::MIDNIGHT, UtcOffset::UTC)
165 .unix_timestamp_nanos()
166 },
167 {
168 OffsetDateTime::new_in_offset(Date::MAX, Time::MAX, UtcOffset::UTC)
169 .unix_timestamp_nanos()
170 },
171 >,
172 offset_is_negative: Option<bool>,
175 pub(super) leap_second_allowed: bool,
178}
179
180impl Default for Parsed {
181 fn default() -> Self {
182 Self::new()
183 }
184}
185
186impl Parsed {
187 pub const fn new() -> Self {
189 Self {
190 year: OptionRangedI32::None,
191 year_last_two: OptionRangedU8::None,
192 iso_year: OptionRangedI32::None,
193 iso_year_last_two: OptionRangedU8::None,
194 month: None,
195 sunday_week_number: OptionRangedU8::None,
196 monday_week_number: OptionRangedU8::None,
197 iso_week_number: OptionRangedU8::None,
198 weekday: None,
199 ordinal: OptionRangedU16::None,
200 day: OptionRangedU8::None,
201 hour_24: OptionRangedU8::None,
202 hour_12: OptionRangedU8::None,
203 hour_12_is_pm: None,
204 minute: OptionRangedU8::None,
205 second: OptionRangedU8::None,
206 subsecond: OptionRangedU32::None,
207 offset_hour: OptionRangedI8::None,
208 offset_minute: OptionRangedI8::None,
209 offset_second: OptionRangedI8::None,
210 unix_timestamp_nanos: OptionRangedI128::None,
211 offset_is_negative: None,
212 leap_second_allowed: false,
213 }
214 }
215
216 pub fn parse_item<'a>(
222 &mut self,
223 input: &'a [u8],
224 item: &impl sealed::AnyFormatItem,
225 ) -> Result<&'a [u8], error::ParseFromDescription> {
226 item.parse_item(self, input)
227 }
228
229 pub fn parse_items<'a>(
235 &mut self,
236 mut input: &'a [u8],
237 items: &[impl sealed::AnyFormatItem],
238 ) -> Result<&'a [u8], error::ParseFromDescription> {
239 let mut this = *self;
242 for item in items {
243 input = this.parse_item(input, item)?;
244 }
245 *self = this;
246 Ok(input)
247 }
248
249 pub fn parse_literal<'a>(
251 input: &'a [u8],
252 literal: &[u8],
253 ) -> Result<&'a [u8], error::ParseFromDescription> {
254 input
255 .strip_prefix(literal)
256 .ok_or(error::ParseFromDescription::InvalidLiteral)
257 }
258
259 pub fn parse_component<'a>(
262 &mut self,
263 input: &'a [u8],
264 component: Component,
265 ) -> Result<&'a [u8], error::ParseFromDescription> {
266 use error::ParseFromDescription::InvalidComponent;
267
268 match component {
269 Component::Day(modifiers) => parse_day(input, modifiers)
270 .and_then(|parsed| parsed.consume_value(|value| self.set_day(value)))
271 .ok_or(InvalidComponent("day")),
272 Component::Month(modifiers) => parse_month(input, modifiers)
273 .and_then(|parsed| parsed.consume_value(|value| self.set_month(value)))
274 .ok_or(InvalidComponent("month")),
275 Component::Ordinal(modifiers) => parse_ordinal(input, modifiers)
276 .and_then(|parsed| parsed.consume_value(|value| self.set_ordinal(value)))
277 .ok_or(InvalidComponent("ordinal")),
278 Component::Weekday(modifiers) => parse_weekday(input, modifiers)
279 .and_then(|parsed| parsed.consume_value(|value| self.set_weekday(value)))
280 .ok_or(InvalidComponent("weekday")),
281 Component::WeekNumber(modifiers) => {
282 let ParsedItem(remaining, value) =
283 parse_week_number(input, modifiers).ok_or(InvalidComponent("week number"))?;
284 match modifiers.repr {
285 modifier::WeekNumberRepr::Iso => {
286 NonZeroU8::new(value).and_then(|value| self.set_iso_week_number(value))
287 }
288 modifier::WeekNumberRepr::Sunday => self.set_sunday_week_number(value),
289 modifier::WeekNumberRepr::Monday => self.set_monday_week_number(value),
290 }
291 .ok_or(InvalidComponent("week number"))?;
292 Ok(remaining)
293 }
294 Component::Year(modifiers) => {
295 let ParsedItem(remaining, value) =
296 parse_year(input, modifiers).ok_or(InvalidComponent("year"))?;
297 match (modifiers.iso_week_based, modifiers.repr) {
298 (false, modifier::YearRepr::Full) => self.set_year(value),
299 (false, modifier::YearRepr::LastTwo) => {
300 self.set_year_last_two(value.cast_unsigned().truncate())
301 }
302 (true, modifier::YearRepr::Full) => self.set_iso_year(value),
303 (true, modifier::YearRepr::LastTwo) => {
304 self.set_iso_year_last_two(value.cast_unsigned().truncate())
305 }
306 }
307 .ok_or(InvalidComponent("year"))?;
308 Ok(remaining)
309 }
310 Component::Hour(modifiers) => {
311 let ParsedItem(remaining, value) =
312 parse_hour(input, modifiers).ok_or(InvalidComponent("hour"))?;
313 if modifiers.is_12_hour_clock {
314 NonZeroU8::new(value).and_then(|value| self.set_hour_12(value))
315 } else {
316 self.set_hour_24(value)
317 }
318 .ok_or(InvalidComponent("hour"))?;
319 Ok(remaining)
320 }
321 Component::Minute(modifiers) => parse_minute(input, modifiers)
322 .and_then(|parsed| parsed.consume_value(|value| self.set_minute(value)))
323 .ok_or(InvalidComponent("minute")),
324 Component::Period(modifiers) => parse_period(input, modifiers)
325 .and_then(|parsed| {
326 parsed.consume_value(|value| self.set_hour_12_is_pm(value == Period::Pm))
327 })
328 .ok_or(InvalidComponent("period")),
329 Component::Second(modifiers) => parse_second(input, modifiers)
330 .and_then(|parsed| parsed.consume_value(|value| self.set_second(value)))
331 .ok_or(InvalidComponent("second")),
332 Component::Subsecond(modifiers) => parse_subsecond(input, modifiers)
333 .and_then(|parsed| parsed.consume_value(|value| self.set_subsecond(value)))
334 .ok_or(InvalidComponent("subsecond")),
335 Component::OffsetHour(modifiers) => parse_offset_hour(input, modifiers)
336 .and_then(|parsed| {
337 parsed.consume_value(|(value, is_negative)| {
338 self.set_offset_hour(value)?;
339 self.offset_is_negative = Some(is_negative);
340 Some(())
341 })
342 })
343 .ok_or(InvalidComponent("offset hour")),
344 Component::OffsetMinute(modifiers) => parse_offset_minute(input, modifiers)
345 .and_then(|parsed| {
346 parsed.consume_value(|value| self.set_offset_minute_signed(value))
347 })
348 .ok_or(InvalidComponent("offset minute")),
349 Component::OffsetSecond(modifiers) => parse_offset_second(input, modifiers)
350 .and_then(|parsed| {
351 parsed.consume_value(|value| self.set_offset_second_signed(value))
352 })
353 .ok_or(InvalidComponent("offset second")),
354 Component::Ignore(modifiers) => parse_ignore(input, modifiers)
355 .map(ParsedItem::<()>::into_inner)
356 .ok_or(InvalidComponent("ignore")),
357 Component::UnixTimestamp(modifiers) => parse_unix_timestamp(input, modifiers)
358 .and_then(|parsed| {
359 parsed.consume_value(|value| self.set_unix_timestamp_nanos(value))
360 })
361 .ok_or(InvalidComponent("unix_timestamp")),
362 Component::End(modifiers) => parse_end(input, modifiers)
363 .map(ParsedItem::<()>::into_inner)
364 .ok_or(error::ParseFromDescription::UnexpectedTrailingCharacters),
365 }
366 }
367}
368
369impl Parsed {
371 pub const fn year(&self) -> Option<i32> {
373 self.year.get_primitive()
374 }
375
376 pub const fn year_last_two(&self) -> Option<u8> {
378 self.year_last_two.get_primitive()
379 }
380
381 pub const fn iso_year(&self) -> Option<i32> {
383 self.iso_year.get_primitive()
384 }
385
386 pub const fn iso_year_last_two(&self) -> Option<u8> {
388 self.iso_year_last_two.get_primitive()
389 }
390
391 pub const fn month(&self) -> Option<Month> {
393 self.month
394 }
395
396 pub const fn sunday_week_number(&self) -> Option<u8> {
398 self.sunday_week_number.get_primitive()
399 }
400
401 pub const fn monday_week_number(&self) -> Option<u8> {
403 self.monday_week_number.get_primitive()
404 }
405
406 pub const fn iso_week_number(&self) -> Option<NonZeroU8> {
408 NonZeroU8::new(const_try_opt!(self.iso_week_number.get_primitive()))
409 }
410
411 pub const fn weekday(&self) -> Option<Weekday> {
413 self.weekday
414 }
415
416 pub const fn ordinal(&self) -> Option<NonZeroU16> {
418 NonZeroU16::new(const_try_opt!(self.ordinal.get_primitive()))
419 }
420
421 pub const fn day(&self) -> Option<NonZeroU8> {
423 NonZeroU8::new(const_try_opt!(self.day.get_primitive()))
424 }
425
426 pub const fn hour_24(&self) -> Option<u8> {
428 self.hour_24.get_primitive()
429 }
430
431 pub const fn hour_12(&self) -> Option<NonZeroU8> {
433 NonZeroU8::new(const_try_opt!(self.hour_12.get_primitive()))
434 }
435
436 pub const fn hour_12_is_pm(&self) -> Option<bool> {
438 self.hour_12_is_pm
439 }
440
441 pub const fn minute(&self) -> Option<u8> {
443 self.minute.get_primitive()
444 }
445
446 pub const fn second(&self) -> Option<u8> {
448 self.second.get_primitive()
449 }
450
451 pub const fn subsecond(&self) -> Option<u32> {
453 self.subsecond.get_primitive()
454 }
455
456 pub const fn offset_hour(&self) -> Option<i8> {
458 self.offset_hour.get_primitive()
459 }
460
461 #[doc(hidden)]
463 #[deprecated(since = "0.3.8", note = "use `parsed.offset_minute_signed()` instead")]
464 pub const fn offset_minute(&self) -> Option<u8> {
465 Some(const_try_opt!(self.offset_minute_signed()).unsigned_abs())
466 }
467
468 pub const fn offset_minute_signed(&self) -> Option<i8> {
470 match (self.offset_minute.get_primitive(), self.offset_is_negative) {
471 (Some(offset_minute), Some(true)) => Some(-offset_minute),
472 (Some(offset_minute), _) => Some(offset_minute),
473 (None, _) => None,
474 }
475 }
476
477 #[doc(hidden)]
479 #[deprecated(since = "0.3.8", note = "use `parsed.offset_second_signed()` instead")]
480 pub const fn offset_second(&self) -> Option<u8> {
481 Some(const_try_opt!(self.offset_second_signed()).unsigned_abs())
482 }
483
484 pub const fn offset_second_signed(&self) -> Option<i8> {
486 match (self.offset_second.get_primitive(), self.offset_is_negative) {
487 (Some(offset_second), Some(true)) => Some(-offset_second),
488 (Some(offset_second), _) => Some(offset_second),
489 (None, _) => None,
490 }
491 }
492
493 pub const fn unix_timestamp_nanos(&self) -> Option<i128> {
495 self.unix_timestamp_nanos.get_primitive()
496 }
497}
498
499macro_rules! setters {
501 ($($name:ident $setter:ident $builder:ident $type:ty;)*) => {$(
502 #[doc = concat!("Set the `", stringify!($setter), "` component.")]
503 pub fn $setter(&mut self, value: $type) -> Option<()> {
504 *self = self.$builder(value)?;
505 Some(())
506 }
507 )*};
508}
509
510impl Parsed {
515 setters! {
516 year set_year with_year i32;
517 year_last_two set_year_last_two with_year_last_two u8;
518 iso_year set_iso_year with_iso_year i32;
519 iso_year_last_two set_iso_year_last_two with_iso_year_last_two u8;
520 month set_month with_month Month;
521 sunday_week_number set_sunday_week_number with_sunday_week_number u8;
522 monday_week_number set_monday_week_number with_monday_week_number u8;
523 iso_week_number set_iso_week_number with_iso_week_number NonZeroU8;
524 weekday set_weekday with_weekday Weekday;
525 ordinal set_ordinal with_ordinal NonZeroU16;
526 day set_day with_day NonZeroU8;
527 hour_24 set_hour_24 with_hour_24 u8;
528 hour_12 set_hour_12 with_hour_12 NonZeroU8;
529 hour_12_is_pm set_hour_12_is_pm with_hour_12_is_pm bool;
530 minute set_minute with_minute u8;
531 second set_second with_second u8;
532 subsecond set_subsecond with_subsecond u32;
533 offset_hour set_offset_hour with_offset_hour i8;
534 offset_minute set_offset_minute_signed with_offset_minute_signed i8;
535 offset_second set_offset_second_signed with_offset_second_signed i8;
536 unix_timestamp_nanos set_unix_timestamp_nanos with_unix_timestamp_nanos i128;
537 }
538
539 #[doc(hidden)]
541 #[deprecated(
542 since = "0.3.8",
543 note = "use `parsed.set_offset_minute_signed()` instead"
544 )]
545 pub fn set_offset_minute(&mut self, value: u8) -> Option<()> {
546 if value > i8::MAX.cast_unsigned() {
547 None
548 } else {
549 self.set_offset_minute_signed(value.cast_signed())
550 }
551 }
552
553 #[doc(hidden)]
555 #[deprecated(
556 since = "0.3.8",
557 note = "use `parsed.set_offset_second_signed()` instead"
558 )]
559 pub fn set_offset_second(&mut self, value: u8) -> Option<()> {
560 if value > i8::MAX.cast_unsigned() {
561 None
562 } else {
563 self.set_offset_second_signed(value.cast_signed())
564 }
565 }
566}
567
568impl Parsed {
573 pub const fn with_year(mut self, value: i32) -> Option<Self> {
575 self.year = OptionRangedI32::Some(const_try_opt!(RangedI32::new(value)));
576 Some(self)
577 }
578
579 pub const fn with_year_last_two(mut self, value: u8) -> Option<Self> {
581 self.year_last_two = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
582 Some(self)
583 }
584
585 pub const fn with_iso_year(mut self, value: i32) -> Option<Self> {
587 self.iso_year = OptionRangedI32::Some(const_try_opt!(RangedI32::new(value)));
588 Some(self)
589 }
590
591 pub const fn with_iso_year_last_two(mut self, value: u8) -> Option<Self> {
593 self.iso_year_last_two = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
594 Some(self)
595 }
596
597 pub const fn with_month(mut self, value: Month) -> Option<Self> {
599 self.month = Some(value);
600 Some(self)
601 }
602
603 pub const fn with_sunday_week_number(mut self, value: u8) -> Option<Self> {
605 self.sunday_week_number = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
606 Some(self)
607 }
608
609 pub const fn with_monday_week_number(mut self, value: u8) -> Option<Self> {
611 self.monday_week_number = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
612 Some(self)
613 }
614
615 pub const fn with_iso_week_number(mut self, value: NonZeroU8) -> Option<Self> {
617 self.iso_week_number = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value.get())));
618 Some(self)
619 }
620
621 pub const fn with_weekday(mut self, value: Weekday) -> Option<Self> {
623 self.weekday = Some(value);
624 Some(self)
625 }
626
627 pub const fn with_ordinal(mut self, value: NonZeroU16) -> Option<Self> {
629 self.ordinal = OptionRangedU16::Some(const_try_opt!(RangedU16::new(value.get())));
630 Some(self)
631 }
632
633 pub const fn with_day(mut self, value: NonZeroU8) -> Option<Self> {
635 self.day = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value.get())));
636 Some(self)
637 }
638
639 pub const fn with_hour_24(mut self, value: u8) -> Option<Self> {
641 self.hour_24 = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
642 Some(self)
643 }
644
645 pub const fn with_hour_12(mut self, value: NonZeroU8) -> Option<Self> {
647 self.hour_12 = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value.get())));
648 Some(self)
649 }
650
651 pub const fn with_hour_12_is_pm(mut self, value: bool) -> Option<Self> {
653 self.hour_12_is_pm = Some(value);
654 Some(self)
655 }
656
657 pub const fn with_minute(mut self, value: u8) -> Option<Self> {
659 self.minute = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
660 Some(self)
661 }
662
663 pub const fn with_second(mut self, value: u8) -> Option<Self> {
665 self.second = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
666 Some(self)
667 }
668
669 pub const fn with_subsecond(mut self, value: u32) -> Option<Self> {
671 self.subsecond = OptionRangedU32::Some(const_try_opt!(RangedU32::new(value)));
672 Some(self)
673 }
674
675 pub const fn with_offset_hour(mut self, value: i8) -> Option<Self> {
677 self.offset_hour = OptionRangedI8::Some(const_try_opt!(RangedI8::new(value)));
678 Some(self)
679 }
680
681 #[doc(hidden)]
683 #[deprecated(
684 since = "0.3.8",
685 note = "use `parsed.with_offset_minute_signed()` instead"
686 )]
687 pub const fn with_offset_minute(self, value: u8) -> Option<Self> {
688 if value > i8::MAX as u8 {
689 None
690 } else {
691 self.with_offset_minute_signed(value as _)
692 }
693 }
694
695 pub const fn with_offset_minute_signed(mut self, value: i8) -> Option<Self> {
697 self.offset_minute = OptionRangedI8::Some(const_try_opt!(RangedI8::new(value)));
698 Some(self)
699 }
700
701 #[doc(hidden)]
703 #[deprecated(
704 since = "0.3.8",
705 note = "use `parsed.with_offset_second_signed()` instead"
706 )]
707 pub const fn with_offset_second(self, value: u8) -> Option<Self> {
708 if value > i8::MAX as u8 {
709 None
710 } else {
711 self.with_offset_second_signed(value as _)
712 }
713 }
714
715 pub const fn with_offset_second_signed(mut self, value: i8) -> Option<Self> {
717 self.offset_second = OptionRangedI8::Some(const_try_opt!(RangedI8::new(value)));
718 Some(self)
719 }
720
721 pub const fn with_unix_timestamp_nanos(mut self, value: i128) -> Option<Self> {
723 self.unix_timestamp_nanos = OptionRangedI128::Some(const_try_opt!(RangedI128::new(value)));
724 Some(self)
725 }
726}
727
728impl TryFrom<Parsed> for Date {
729 type Error = error::TryFromParsed;
730
731 fn try_from(parsed: Parsed) -> Result<Self, Self::Error> {
732 macro_rules! match_ {
734 (_ => $catch_all:expr $(,)?) => {
735 $catch_all
736 };
737 (($($name:ident),* $(,)?) => $arm:expr, $($rest:tt)*) => {
738 if let ($(Some($name)),*) = ($(parsed.$name()),*) {
739 $arm
740 } else {
741 match_!($($rest)*)
742 }
743 };
744 }
745
746 const fn adjustment(year: i32) -> i16 {
749 match unsafe { Date::__from_ordinal_date_unchecked(year, 1) }.weekday() {
751 Weekday::Monday => 7,
752 Weekday::Tuesday => 1,
753 Weekday::Wednesday => 2,
754 Weekday::Thursday => 3,
755 Weekday::Friday => 4,
756 Weekday::Saturday => 5,
757 Weekday::Sunday => 6,
758 }
759 }
760
761 match_! {
765 (year, ordinal) => Ok(Self::from_ordinal_date(year, ordinal.get())?),
766 (year, month, day) => Ok(Self::from_calendar_date(year, month, day.get())?),
767 (iso_year, iso_week_number, weekday) => Ok(Self::from_iso_week_date(
768 iso_year,
769 iso_week_number.get(),
770 weekday,
771 )?),
772 (year, sunday_week_number, weekday) => Ok(Self::from_ordinal_date(
773 year,
774 (sunday_week_number.cast_signed().extend::<i16>() * 7
775 + weekday.number_days_from_sunday().cast_signed().extend::<i16>()
776 - adjustment(year)
777 + 1).cast_unsigned(),
778 )?),
779 (year, monday_week_number, weekday) => Ok(Self::from_ordinal_date(
780 year,
781 (monday_week_number.cast_signed().extend::<i16>() * 7
782 + weekday.number_days_from_monday().cast_signed().extend::<i16>()
783 - adjustment(year)
784 + 1).cast_unsigned(),
785 )?),
786 _ => Err(InsufficientInformation),
787 }
788 }
789}
790
791impl TryFrom<Parsed> for Time {
792 type Error = error::TryFromParsed;
793
794 fn try_from(parsed: Parsed) -> Result<Self, Self::Error> {
795 let hour = match (parsed.hour_24(), parsed.hour_12(), parsed.hour_12_is_pm()) {
796 (Some(hour), _, _) => hour,
797 (_, Some(hour), Some(false)) if hour.get() == 12 => 0,
798 (_, Some(hour), Some(true)) if hour.get() == 12 => 12,
799 (_, Some(hour), Some(false)) => hour.get(),
800 (_, Some(hour), Some(true)) => hour.get() + 12,
801 _ => return Err(InsufficientInformation),
802 };
803
804 if parsed.hour_24().is_none()
805 && parsed.hour_12().is_some()
806 && parsed.hour_12_is_pm().is_some()
807 && parsed.minute().is_none()
808 && parsed.second().is_none()
809 && parsed.subsecond().is_none()
810 {
811 return Ok(Self::from_hms_nano(hour, 0, 0, 0)?);
812 }
813
814 match (parsed.minute(), parsed.second(), parsed.subsecond()) {
816 (None, None, None) => Ok(Self::from_hms_nano(hour, 0, 0, 0)?),
817 (Some(minute), None, None) => Ok(Self::from_hms_nano(hour, minute, 0, 0)?),
818 (Some(minute), Some(second), None) => Ok(Self::from_hms_nano(hour, minute, second, 0)?),
819 (Some(minute), Some(second), Some(subsecond)) => {
820 Ok(Self::from_hms_nano(hour, minute, second, subsecond)?)
821 }
822 _ => Err(InsufficientInformation),
823 }
824 }
825}
826
827impl TryFrom<Parsed> for UtcOffset {
828 type Error = error::TryFromParsed;
829
830 fn try_from(parsed: Parsed) -> Result<Self, Self::Error> {
831 let hour = parsed.offset_hour().ok_or(InsufficientInformation)?;
832 let minute = parsed.offset_minute_signed().unwrap_or(0);
833 let second = parsed.offset_second_signed().unwrap_or(0);
834
835 Self::from_hms(hour, minute, second).map_err(|mut err| {
836 if err.name == "hours" {
838 err.name = "offset hour";
839 } else if err.name == "minutes" {
840 err.name = "offset minute";
841 } else if err.name == "seconds" {
842 err.name = "offset second";
843 }
844 err.into()
845 })
846 }
847}
848
849impl TryFrom<Parsed> for PrimitiveDateTime {
850 type Error = error::TryFromParsed;
851
852 fn try_from(parsed: Parsed) -> Result<Self, Self::Error> {
853 Ok(Self::new(parsed.try_into()?, parsed.try_into()?))
854 }
855}
856
857impl TryFrom<Parsed> for OffsetDateTime {
858 type Error = error::TryFromParsed;
859
860 fn try_from(mut parsed: Parsed) -> Result<Self, Self::Error> {
861 if let Some(timestamp) = parsed.unix_timestamp_nanos() {
862 let mut value = Self::from_unix_timestamp_nanos(timestamp)?;
863 if let Some(subsecond) = parsed.subsecond() {
864 value = value.replace_nanosecond(subsecond)?;
865 }
866 return Ok(value);
867 }
868
869 let leap_second_input = if parsed.leap_second_allowed && parsed.second() == Some(60) {
873 if parsed.set_second(59).is_none() {
874 bug!("59 is a valid second");
875 }
876 if parsed.set_subsecond(999_999_999).is_none() {
877 bug!("999_999_999 is a valid subsecond");
878 }
879 true
880 } else {
881 false
882 };
883
884 let dt = Self::new_in_offset(
885 Date::try_from(parsed)?,
886 Time::try_from(parsed)?,
887 UtcOffset::try_from(parsed)?,
888 );
889
890 if leap_second_input && !dt.is_valid_leap_second_stand_in() {
891 return Err(error::TryFromParsed::ComponentRange(
892 error::ComponentRange {
893 name: "second",
894 minimum: 0,
895 maximum: 59,
896 value: 60,
897 conditional_range: true,
898 },
899 ));
900 }
901 Ok(dt)
902 }
903}