Skip to main content

time/parsing/
parsed.rs

1//! Information parsed from an input and format description.
2
3use core::num::NonZero;
4
5use deranged::{
6    Option_ri8, Option_ri16, Option_ri32, Option_ri128, Option_ru8, Option_ru16, Option_ru32, ri8,
7    ri16, ri32, ri128, ru8, ru16, ru32,
8};
9use num_conv::prelude::*;
10
11use crate::date::{MAX_YEAR, MIN_YEAR};
12use crate::error::TryFromParsed::InsufficientInformation;
13#[cfg(feature = "alloc")]
14use crate::format_description::OwnedFormatItem;
15use crate::format_description::{BorrowedFormatItem, Component, Period, modifier};
16use crate::internal_macros::{bug, const_try_opt};
17use crate::parsing::ParsedItem;
18use crate::parsing::component::{
19    parse_calendar_year_century_extended_range, parse_calendar_year_century_standard_range,
20    parse_calendar_year_full_extended_range, parse_calendar_year_full_standard_range,
21    parse_calendar_year_last_two, parse_day, parse_end, parse_hour_12, parse_hour_24, parse_ignore,
22    parse_iso_year_century_extended_range, parse_iso_year_century_standard_range,
23    parse_iso_year_full_extended_range, parse_iso_year_full_standard_range,
24    parse_iso_year_last_two, parse_minute, parse_month_long, parse_month_numerical,
25    parse_month_short, parse_offset_hour, parse_offset_minute, parse_offset_second, parse_ordinal,
26    parse_period, parse_second, parse_subsecond, parse_unix_timestamp_microsecond,
27    parse_unix_timestamp_millisecond, parse_unix_timestamp_nanosecond, parse_unix_timestamp_second,
28    parse_week_number_iso, parse_week_number_monday, parse_week_number_sunday, parse_weekday_long,
29    parse_weekday_monday, parse_weekday_short, parse_weekday_sunday, parse_year,
30};
31use crate::unit::{Day, Hour, Minute, Nanosecond, Second};
32use crate::{
33    Date, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcDateTime, UtcOffset, Weekday, error,
34};
35
36/// Sealed to prevent downstream implementations.
37mod sealed {
38    use super::*;
39
40    /// A trait to allow `parse_item` to be generic.
41    pub trait AnyFormatItem {
42        /// Parse a single item, returning the remaining input on success.
43        fn parse_item<'a>(
44            &self,
45            parsed: &mut Parsed,
46            input: &'a [u8],
47        ) -> Result<&'a [u8], error::ParseFromDescription>;
48    }
49}
50
51impl sealed::AnyFormatItem for BorrowedFormatItem<'_> {
52    #[inline(always)]
53    fn parse_item<'a>(
54        &self,
55        parsed: &mut Parsed,
56        input: &'a [u8],
57    ) -> Result<&'a [u8], error::ParseFromDescription> {
58        match self {
59            #[expect(deprecated)]
60            Self::Literal(literal) => Parsed::parse_literal(input, literal),
61            Self::StringLiteral(literal) => Parsed::parse_literal(input, literal.as_bytes()),
62            Self::Component(component) => parsed.parse_component(input, *component),
63            Self::Compound(compound) => parsed.parse_items(input, compound),
64            Self::Optional(item) => parsed.parse_item(input, *item).or(Ok(input)),
65            Self::First(items) => {
66                let mut first_err = None;
67
68                for item in items.iter() {
69                    match parsed.parse_item(input, item) {
70                        Ok(remaining_input) => return Ok(remaining_input),
71                        Err(err) if first_err.is_none() => first_err = Some(err),
72                        Err(_) => {}
73                    }
74                }
75
76                match first_err {
77                    Some(err) => Err(err),
78                    // This location will be reached if the slice is empty, skipping the `for` loop.
79                    // As this case is expected to be uncommon, there's no need to check up front.
80                    None => Ok(input),
81                }
82            }
83        }
84    }
85}
86
87#[cfg(feature = "alloc")]
88impl sealed::AnyFormatItem for OwnedFormatItem {
89    #[inline]
90    fn parse_item<'a>(
91        &self,
92        parsed: &mut Parsed,
93        input: &'a [u8],
94    ) -> Result<&'a [u8], error::ParseFromDescription> {
95        match self {
96            #[expect(deprecated)]
97            Self::Literal(literal) => Parsed::parse_literal(input, literal),
98            Self::StringLiteral(literal) => Parsed::parse_literal(input, literal.as_bytes()),
99            Self::Component(component) => parsed.parse_component(input, *component),
100            Self::Compound(compound) => parsed.parse_items(input, compound),
101            Self::Optional(item) => parsed.parse_item(input, item.as_ref()).or(Ok(input)),
102            Self::First(items) => {
103                let mut first_err = None;
104
105                for item in items.iter() {
106                    match parsed.parse_item(input, item) {
107                        Ok(remaining_input) => return Ok(remaining_input),
108                        Err(err) if first_err.is_none() => first_err = Some(err),
109                        Err(_) => {}
110                    }
111                }
112
113                match first_err {
114                    Some(err) => Err(err),
115                    // This location will be reached if the slice is empty, skipping the `for` loop.
116                    // As this case is expected to be uncommon, there's no need to check up front.
117                    None => Ok(input),
118                }
119            }
120        }
121    }
122}
123
124/// All information parsed.
125///
126/// This information is directly used to construct the final values.
127///
128/// Most users will not need think about this struct in any way. It is public to allow for manual
129/// control over values, in the instance that the default parser is insufficient.
130#[derive(Debug, Clone, Copy)]
131pub struct Parsed {
132    /// Calendar year.
133    year: Option_ri32<{ MIN_YEAR }, { MAX_YEAR }>,
134    /// All digits except the last two of the calendar year.
135    year_century: Option_ri16<{ (MIN_YEAR / 100) as i16 }, { (MAX_YEAR / 100) as i16 }>,
136    /// The last two digits of the calendar year.
137    year_last_two: Option_ru8<0, 99>,
138    /// Year of the [ISO week date](https://en.wikipedia.org/wiki/ISO_week_date).
139    iso_year: Option_ri32<{ MIN_YEAR }, { MAX_YEAR }>,
140    /// All digits except the last two of the ISO week year.
141    iso_year_century: Option_ri16<{ (MIN_YEAR / 100) as i16 }, { (MAX_YEAR / 100) as i16 }>,
142    /// The last two digits of the ISO week year.
143    iso_year_last_two: Option_ru8<0, 99>,
144    /// Month of the year.
145    month: Option<Month>,
146    /// Week of the year, where week one begins on the first Sunday of the calendar year.
147    sunday_week_number: Option_ru8<0, 53>,
148    /// Week of the year, where week one begins on the first Monday of the calendar year.
149    monday_week_number: Option_ru8<0, 53>,
150    /// Week of the year, where week one is the Monday-to-Sunday period containing January 4.
151    iso_week_number: Option_ru8<1, 53>,
152    /// Day of the week.
153    weekday: Option<Weekday>,
154    /// Day of the year.
155    ordinal: Option_ru16<1, 366>,
156    /// Day of the month.
157    day: Option_ru8<1, 31>,
158    /// Hour within the day.
159    hour_24: Option_ru8<0, { Hour::per_t::<u8>(Day) - 1 }>,
160    /// Hour within the 12-hour period (midnight to noon or vice versa). This is typically used in
161    /// conjunction with AM/PM, which is indicated by the `hour_12_is_pm` field.
162    hour_12: Option_ru8<1, 12>,
163    /// Whether the `hour_12` field indicates a time that "PM".
164    hour_12_is_pm: Option<bool>,
165    /// Minute within the hour.
166    minute: Option_ru8<0, { Minute::per_t::<u8>(Hour) - 1 }>,
167    /// Second within the minute.
168    // do not subtract one, as leap seconds may be allowed
169    second: Option_ru8<0, { Second::per_t::<u8>(Minute) }>,
170    /// Nanosecond within the second.
171    subsecond: Option_ru32<0, { Nanosecond::per_t::<u32>(Second) - 1 }>,
172    /// Whole hours of the UTC offset.
173    offset_hour: Option_ri8<-23, 23>,
174    /// Minutes within the hour of the UTC offset.
175    offset_minute:
176        Option_ri8<{ -Minute::per_t::<i8>(Hour) + 1 }, { Minute::per_t::<i8>(Hour) - 1 }>,
177    /// Seconds within the minute of the UTC offset.
178    offset_second:
179        Option_ri8<{ -Second::per_t::<i8>(Minute) + 1 }, { Second::per_t::<i8>(Minute) - 1 }>,
180    /// The Unix timestamp in nanoseconds.
181    unix_timestamp_nanos: Option_ri128<
182        {
183            OffsetDateTime::new_in_offset(Date::MIN, Time::MIDNIGHT, UtcOffset::UTC)
184                .unix_timestamp_nanos()
185        },
186        {
187            OffsetDateTime::new_in_offset(Date::MAX, Time::MAX, UtcOffset::UTC)
188                .unix_timestamp_nanos()
189        },
190    >,
191    /// Indicates whether the [`UtcOffset`] is negative. This information is obtained when parsing
192    /// the offset hour, but may not otherwise be stored due to "-0" being equivalent to "0".
193    offset_is_negative: bool,
194    /// Indicates whether the `year_century` component is negative. This information is obtained
195    /// when parsing, but may not otherwise be stored due to "-0" being equivalent to "0".
196    year_century_is_negative: bool,
197    /// Indicates whether the `iso_year_century` component is negative. This information is
198    /// obtained when parsing, but may not otherwise be stored due to "-0" being equivalent to "0".
199    iso_year_century_is_negative: bool,
200    /// Indicates whether a leap second is permitted to be parsed. This is required by some
201    /// well-known formats.
202    pub(super) leap_second_allowed: bool,
203}
204
205impl Default for Parsed {
206    #[inline]
207    fn default() -> Self {
208        Self::new()
209    }
210}
211
212impl Parsed {
213    /// Create a new instance of `Parsed` with no information known.
214    #[inline]
215    pub const fn new() -> Self {
216        Self {
217            year: Option_ri32::None,
218            year_century: Option_ri16::None,
219            year_last_two: Option_ru8::None,
220            iso_year: Option_ri32::None,
221            iso_year_century: Option_ri16::None,
222            iso_year_last_two: Option_ru8::None,
223            month: None,
224            sunday_week_number: Option_ru8::None,
225            monday_week_number: Option_ru8::None,
226            iso_week_number: Option_ru8::None,
227            weekday: None,
228            ordinal: Option_ru16::None,
229            day: Option_ru8::None,
230            hour_24: Option_ru8::None,
231            hour_12: Option_ru8::None,
232            hour_12_is_pm: None,
233            minute: Option_ru8::None,
234            second: Option_ru8::None,
235            subsecond: Option_ru32::None,
236            offset_hour: Option_ri8::None,
237            offset_minute: Option_ri8::None,
238            offset_second: Option_ri8::None,
239            unix_timestamp_nanos: Option_ri128::None,
240            offset_is_negative: false,
241            year_century_is_negative: false,
242            iso_year_century_is_negative: false,
243            leap_second_allowed: false,
244        }
245    }
246
247    /// Parse a single [`BorrowedFormatItem`] or [`OwnedFormatItem`], mutating the struct. The
248    /// remaining input is returned as the `Ok` value.
249    ///
250    /// If a [`BorrowedFormatItem::Optional`] or [`OwnedFormatItem::Optional`] is passed, parsing
251    /// will not fail; the input will be returned as-is if the expected format is not present.
252    #[inline]
253    pub fn parse_item<'a>(
254        &mut self,
255        input: &'a [u8],
256        item: &impl sealed::AnyFormatItem,
257    ) -> Result<&'a [u8], error::ParseFromDescription> {
258        item.parse_item(self, input)
259    }
260
261    /// Parse a sequence of [`BorrowedFormatItem`]s or [`OwnedFormatItem`]s, mutating the struct.
262    /// The remaining input is returned as the `Ok` value.
263    ///
264    /// This method will fail if any of the contained [`BorrowedFormatItem`]s or
265    /// [`OwnedFormatItem`]s fail to parse. `self` will not be mutated in this instance.
266    #[inline]
267    pub fn parse_items<'a>(
268        &mut self,
269        mut input: &'a [u8],
270        items: &[impl sealed::AnyFormatItem],
271    ) -> Result<&'a [u8], error::ParseFromDescription> {
272        // Make a copy that we can mutate. It will only be set to the user's copy if everything
273        // succeeds.
274        let mut this = *self;
275        for item in items {
276            input = this.parse_item(input, item)?;
277        }
278        *self = this;
279        Ok(input)
280    }
281
282    /// Parse a literal byte sequence. The remaining input is returned as the `Ok` value.
283    #[inline]
284    pub fn parse_literal<'a>(
285        input: &'a [u8],
286        literal: &[u8],
287    ) -> Result<&'a [u8], error::ParseFromDescription> {
288        input
289            .strip_prefix(literal)
290            .ok_or(error::ParseFromDescription::InvalidLiteral)
291    }
292
293    /// Parse a single component, mutating the struct. The remaining input is returned as the `Ok`
294    /// value.
295    #[inline]
296    pub fn parse_component<'a>(
297        &mut self,
298        input: &'a [u8],
299        component: Component,
300    ) -> Result<&'a [u8], error::ParseFromDescription> {
301        use error::ParseFromDescription::InvalidComponent;
302
303        match component {
304            Component::Day(modifiers) => parse_day(input, modifiers)
305                .and_then(|parsed| parsed.consume_value(|value| self.set_day(value)))
306                .ok_or(InvalidComponent("day")),
307            Component::MonthShort(modifiers) => parse_month_short(input, modifiers)
308                .and_then(|parsed| parsed.consume_value(|value| self.set_month(value)))
309                .ok_or(InvalidComponent("month")),
310            Component::MonthLong(modifiers) => parse_month_long(input, modifiers)
311                .and_then(|parsed| parsed.consume_value(|value| self.set_month(value)))
312                .ok_or(InvalidComponent("month")),
313            Component::MonthNumerical(modifiers) => parse_month_numerical(input, modifiers)
314                .and_then(|parsed| parsed.consume_value(|value| self.set_month(value)))
315                .ok_or(InvalidComponent("month")),
316            Component::Ordinal(modifiers) => parse_ordinal(input, modifiers)
317                .and_then(|parsed| parsed.consume_value(|value| self.set_ordinal(value)))
318                .ok_or(InvalidComponent("ordinal")),
319            Component::WeekdayShort(modifiers) => parse_weekday_short(input, modifiers)
320                .and_then(|parsed| parsed.consume_value(|value| self.set_weekday(value)))
321                .ok_or(InvalidComponent("weekday")),
322            Component::WeekdayLong(modifiers) => parse_weekday_long(input, modifiers)
323                .and_then(|parsed| parsed.consume_value(|value| self.set_weekday(value)))
324                .ok_or(InvalidComponent("weekday")),
325            Component::WeekdaySunday(modifiers) => parse_weekday_sunday(input, modifiers)
326                .and_then(|parsed| parsed.consume_value(|value| self.set_weekday(value)))
327                .ok_or(InvalidComponent("weekday")),
328            Component::WeekdayMonday(modifiers) => parse_weekday_monday(input, modifiers)
329                .and_then(|parsed| parsed.consume_value(|value| self.set_weekday(value)))
330                .ok_or(InvalidComponent("weekday")),
331            Component::WeekNumberIso(modifiers) => parse_week_number_iso(input, modifiers)
332                .and_then(|parsed| {
333                    parsed.consume_value(|value| self.set_iso_week_number(NonZero::new(value)?))
334                })
335                .ok_or(InvalidComponent("week number")),
336            Component::WeekNumberSunday(modifiers) => parse_week_number_sunday(input, modifiers)
337                .and_then(|parsed| parsed.consume_value(|value| self.set_sunday_week_number(value)))
338                .ok_or(InvalidComponent("week number")),
339            Component::WeekNumberMonday(modifiers) => parse_week_number_monday(input, modifiers)
340                .and_then(|parsed| parsed.consume_value(|value| self.set_monday_week_number(value)))
341                .ok_or(InvalidComponent("week number")),
342            Component::CalendarYearFullExtendedRange(modifiers) => {
343                parse_calendar_year_full_extended_range(input, modifiers)
344                    .and_then(|parsed| parsed.consume_value(|value| self.set_year(value)))
345                    .ok_or(InvalidComponent("year"))
346            }
347            Component::CalendarYearFullStandardRange(modifiers) => {
348                parse_calendar_year_full_standard_range(input, modifiers)
349                    .and_then(|parsed| parsed.consume_value(|value| self.set_year(value)))
350                    .ok_or(InvalidComponent("year"))
351            }
352            Component::IsoYearFullExtendedRange(modifiers) => {
353                parse_iso_year_full_extended_range(input, modifiers)
354                    .and_then(|parsed| parsed.consume_value(|value| self.set_iso_year(value)))
355                    .ok_or(InvalidComponent("year"))
356            }
357            Component::IsoYearFullStandardRange(modifiers) => {
358                parse_iso_year_full_standard_range(input, modifiers)
359                    .and_then(|parsed| parsed.consume_value(|value| self.set_iso_year(value)))
360                    .ok_or(InvalidComponent("year"))
361            }
362            Component::CalendarYearCenturyExtendedRange(modifiers) => {
363                parse_calendar_year_century_extended_range(input, modifiers)
364                    .and_then(|parsed| {
365                        parsed.consume_value(|(value, is_negative)| {
366                            self.set_year_century(value, is_negative)
367                        })
368                    })
369                    .ok_or(InvalidComponent("year"))
370            }
371            Component::CalendarYearCenturyStandardRange(modifiers) => {
372                parse_calendar_year_century_standard_range(input, modifiers)
373                    .and_then(|parsed| {
374                        parsed.consume_value(|(value, is_negative)| {
375                            self.set_year_century(value, is_negative)
376                        })
377                    })
378                    .ok_or(InvalidComponent("year"))
379            }
380            Component::IsoYearCenturyExtendedRange(modifiers) => {
381                parse_iso_year_century_extended_range(input, modifiers)
382                    .and_then(|parsed| {
383                        parsed.consume_value(|(value, is_negative)| {
384                            self.set_iso_year_century(value, is_negative)
385                        })
386                    })
387                    .ok_or(InvalidComponent("year"))
388            }
389            Component::IsoYearCenturyStandardRange(modifiers) => {
390                parse_iso_year_century_standard_range(input, modifiers)
391                    .and_then(|parsed| {
392                        parsed.consume_value(|(value, is_negative)| {
393                            self.set_iso_year_century(value, is_negative)
394                        })
395                    })
396                    .ok_or(InvalidComponent("year"))
397            }
398            Component::CalendarYearLastTwo(modifiers) => {
399                parse_calendar_year_last_two(input, modifiers)
400                    .and_then(|parsed| parsed.consume_value(|value| self.set_year_last_two(value)))
401                    .ok_or(InvalidComponent("year"))
402            }
403            Component::IsoYearLastTwo(modifiers) => parse_iso_year_last_two(input, modifiers)
404                .and_then(|parsed| parsed.consume_value(|value| self.set_iso_year_last_two(value)))
405                .ok_or(InvalidComponent("year")),
406            Component::Hour12(modifiers) => parse_hour_12(input, modifiers)
407                .and_then(|parsed| {
408                    parsed.consume_value(|value| self.set_hour_12(NonZero::new(value)?))
409                })
410                .ok_or(InvalidComponent("hour")),
411            Component::Hour24(modifiers) => parse_hour_24(input, modifiers)
412                .and_then(|parsed| parsed.consume_value(|value| self.set_hour_24(value)))
413                .ok_or(InvalidComponent("hour")),
414            Component::Minute(modifiers) => parse_minute(input, modifiers)
415                .and_then(|parsed| parsed.consume_value(|value| self.set_minute(value)))
416                .ok_or(InvalidComponent("minute")),
417            Component::Period(modifiers) => parse_period(input, modifiers)
418                .and_then(|parsed| {
419                    parsed.consume_value(|value| self.set_hour_12_is_pm(value == Period::Pm))
420                })
421                .ok_or(InvalidComponent("period")),
422            Component::Second(modifiers) => parse_second(input, modifiers)
423                .and_then(|parsed| parsed.consume_value(|value| self.set_second(value)))
424                .ok_or(InvalidComponent("second")),
425            Component::Subsecond(modifiers) => parse_subsecond(input, modifiers)
426                .and_then(|parsed| parsed.consume_value(|value| self.set_subsecond(value)))
427                .ok_or(InvalidComponent("subsecond")),
428            Component::OffsetHour(modifiers) => parse_offset_hour(input, modifiers)
429                .and_then(|parsed| {
430                    parsed.consume_value(|(value, is_negative)| {
431                        self.set_offset_hour(value)?;
432                        self.offset_is_negative = is_negative;
433                        Some(())
434                    })
435                })
436                .ok_or(InvalidComponent("offset hour")),
437            Component::OffsetMinute(modifiers) => parse_offset_minute(input, modifiers)
438                .and_then(|parsed| {
439                    parsed.consume_value(|value| self.set_offset_minute_signed(value))
440                })
441                .ok_or(InvalidComponent("offset minute")),
442            Component::OffsetSecond(modifiers) => parse_offset_second(input, modifiers)
443                .and_then(|parsed| {
444                    parsed.consume_value(|value| self.set_offset_second_signed(value))
445                })
446                .ok_or(InvalidComponent("offset second")),
447            Component::Ignore(modifiers) => parse_ignore(input, modifiers)
448                .map(ParsedItem::<()>::into_inner)
449                .ok_or(InvalidComponent("ignore")),
450            Component::UnixTimestampSecond(modifiers) => {
451                parse_unix_timestamp_second(input, modifiers)
452                    .and_then(|parsed| {
453                        parsed.consume_value(|value| self.set_unix_timestamp_nanos(value))
454                    })
455                    .ok_or(InvalidComponent("unix_timestamp"))
456            }
457            Component::UnixTimestampMillisecond(modifiers) => {
458                parse_unix_timestamp_millisecond(input, modifiers)
459                    .and_then(|parsed| {
460                        parsed.consume_value(|value| self.set_unix_timestamp_nanos(value))
461                    })
462                    .ok_or(InvalidComponent("unix_timestamp"))
463            }
464            Component::UnixTimestampMicrosecond(modifiers) => {
465                parse_unix_timestamp_microsecond(input, modifiers)
466                    .and_then(|parsed| {
467                        parsed.consume_value(|value| self.set_unix_timestamp_nanos(value))
468                    })
469                    .ok_or(InvalidComponent("unix_timestamp"))
470            }
471            Component::UnixTimestampNanosecond(modifiers) => {
472                parse_unix_timestamp_nanosecond(input, modifiers)
473                    .and_then(|parsed| {
474                        parsed.consume_value(|value| self.set_unix_timestamp_nanos(value))
475                    })
476                    .ok_or(InvalidComponent("unix_timestamp"))
477            }
478            Component::End(modifiers) => parse_end(input, modifiers)
479                .map(ParsedItem::<()>::into_inner)
480                .ok_or(error::ParseFromDescription::UnexpectedTrailingCharacters),
481
482            // Start of deprecated components. These are no longer emitted by macros or parsers, so
483            // they should be last for performance reasons as they're unlikely to be encountered.
484            #[expect(deprecated)]
485            Component::Month(modifiers) => match modifiers.repr {
486                modifier::MonthRepr::Short => parse_month_short(
487                    input,
488                    modifier::MonthShort {
489                        case_sensitive: modifiers.case_sensitive,
490                    },
491                ),
492                modifier::MonthRepr::Long => parse_month_long(
493                    input,
494                    modifier::MonthLong {
495                        case_sensitive: modifiers.case_sensitive,
496                    },
497                ),
498                modifier::MonthRepr::Numerical => parse_month_numerical(
499                    input,
500                    modifier::MonthNumerical {
501                        padding: modifiers.padding,
502                    },
503                ),
504            }
505            .and_then(|parsed| parsed.consume_value(|value| self.set_month(value)))
506            .ok_or(InvalidComponent("month")),
507            #[expect(deprecated)]
508            Component::Hour(modifiers) => if modifiers.is_12_hour_clock {
509                parse_hour_12(
510                    input,
511                    modifier::Hour12 {
512                        padding: modifiers.padding,
513                    },
514                )
515                .and_then(|parsed| {
516                    parsed.consume_value(|value| self.set_hour_12(NonZero::new(value)?))
517                })
518            } else {
519                parse_hour_24(
520                    input,
521                    modifier::Hour24 {
522                        padding: modifiers.padding,
523                    },
524                )
525                .and_then(|parsed| parsed.consume_value(|value| self.set_hour_24(value)))
526            }
527            .ok_or(InvalidComponent("hour")),
528            #[expect(deprecated)]
529            Component::WeekNumber(modifiers) => match modifiers.repr {
530                modifier::WeekNumberRepr::Iso => parse_week_number_iso(
531                    input,
532                    modifier::WeekNumberIso {
533                        padding: modifiers.padding,
534                    },
535                )
536                .and_then(|parsed| {
537                    parsed.consume_value(|value| self.set_iso_week_number(NonZero::new(value)?))
538                }),
539                modifier::WeekNumberRepr::Sunday => parse_week_number_sunday(
540                    input,
541                    modifier::WeekNumberSunday {
542                        padding: modifiers.padding,
543                    },
544                )
545                .and_then(|parsed| {
546                    parsed.consume_value(|value| self.set_sunday_week_number(value))
547                }),
548                modifier::WeekNumberRepr::Monday => parse_week_number_monday(
549                    input,
550                    modifier::WeekNumberMonday {
551                        padding: modifiers.padding,
552                    },
553                )
554                .and_then(|parsed| {
555                    parsed.consume_value(|value| self.set_monday_week_number(value))
556                }),
557            }
558            .ok_or(InvalidComponent("week number")),
559            #[expect(deprecated)]
560            Component::Weekday(modifiers) => match modifiers.repr {
561                modifier::WeekdayRepr::Short => parse_weekday_short(
562                    input,
563                    modifier::WeekdayShort {
564                        case_sensitive: modifiers.case_sensitive,
565                    },
566                ),
567                modifier::WeekdayRepr::Long => parse_weekday_long(
568                    input,
569                    modifier::WeekdayLong {
570                        case_sensitive: modifiers.case_sensitive,
571                    },
572                ),
573                modifier::WeekdayRepr::Sunday => parse_weekday_sunday(
574                    input,
575                    modifier::WeekdaySunday {
576                        one_indexed: modifiers.one_indexed,
577                    },
578                ),
579                modifier::WeekdayRepr::Monday => parse_weekday_monday(
580                    input,
581                    modifier::WeekdayMonday {
582                        one_indexed: modifiers.one_indexed,
583                    },
584                ),
585            }
586            .and_then(|parsed| parsed.consume_value(|value| self.set_weekday(value)))
587            .ok_or(InvalidComponent("weekday")),
588            #[expect(deprecated)]
589            Component::UnixTimestamp(modifiers) => match modifiers.precision {
590                modifier::UnixTimestampPrecision::Second => parse_unix_timestamp_second(
591                    input,
592                    modifier::UnixTimestampSecond {
593                        sign_is_mandatory: modifiers.sign_is_mandatory,
594                    },
595                ),
596                modifier::UnixTimestampPrecision::Millisecond => parse_unix_timestamp_millisecond(
597                    input,
598                    modifier::UnixTimestampMillisecond {
599                        sign_is_mandatory: modifiers.sign_is_mandatory,
600                    },
601                ),
602                modifier::UnixTimestampPrecision::Microsecond => parse_unix_timestamp_microsecond(
603                    input,
604                    modifier::UnixTimestampMicrosecond {
605                        sign_is_mandatory: modifiers.sign_is_mandatory,
606                    },
607                ),
608                modifier::UnixTimestampPrecision::Nanosecond => parse_unix_timestamp_nanosecond(
609                    input,
610                    modifier::UnixTimestampNanosecond {
611                        sign_is_mandatory: modifiers.sign_is_mandatory,
612                    },
613                ),
614            }
615            .and_then(|parsed| parsed.consume_value(|value| self.set_unix_timestamp_nanos(value)))
616            .ok_or(InvalidComponent("unix_timestamp")),
617            #[expect(deprecated)]
618            Component::Year(modifiers) => {
619                let ParsedItem(remaining, (value, is_negative)) =
620                    parse_year(input, modifiers).ok_or(InvalidComponent("year"))?;
621                match (modifiers.iso_week_based, modifiers.repr) {
622                    (false, modifier::YearRepr::Full) => self.set_year(value),
623                    (false, modifier::YearRepr::Century) => {
624                        self.set_year_century(value.truncate(), is_negative)
625                    }
626                    (false, modifier::YearRepr::LastTwo) => {
627                        self.set_year_last_two(value.cast_unsigned().truncate())
628                    }
629                    (true, modifier::YearRepr::Full) => self.set_iso_year(value),
630                    (true, modifier::YearRepr::Century) => {
631                        self.set_iso_year_century(value.truncate(), is_negative)
632                    }
633                    (true, modifier::YearRepr::LastTwo) => {
634                        self.set_iso_year_last_two(value.cast_unsigned().truncate())
635                    }
636                }
637                .ok_or(InvalidComponent("year"))?;
638                Ok(remaining)
639            }
640        }
641    }
642}
643
644/// Getter methods
645impl Parsed {
646    /// Obtain the `year` component.
647    #[inline]
648    pub const fn year(&self) -> Option<i32> {
649        self.year.get_primitive()
650    }
651
652    /// Obtain the `year_century` component.
653    ///
654    /// If the year is zero, the sign of the century is not stored. To differentiate between
655    /// positive and negative zero, use `year_century_is_negative`.
656    #[inline]
657    pub const fn year_century(&self) -> Option<i16> {
658        self.year_century.get_primitive()
659    }
660
661    /// Obtain the `year_century_is_negative` component.
662    ///
663    /// This indicates whether the value returned from `year_century` is negative. If the year is
664    /// zero, it is necessary to call this method for disambiguation.
665    #[inline]
666    pub const fn year_century_is_negative(&self) -> Option<bool> {
667        match self.year_century() {
668            Some(_) => Some(self.year_century_is_negative),
669            None => None,
670        }
671    }
672
673    /// Obtain the `year_last_two` component.
674    #[inline]
675    pub const fn year_last_two(&self) -> Option<u8> {
676        self.year_last_two.get_primitive()
677    }
678
679    /// Obtain the `iso_year` component.
680    #[inline]
681    pub const fn iso_year(&self) -> Option<i32> {
682        self.iso_year.get_primitive()
683    }
684
685    /// Obtain the `iso_year_century` component.
686    ///
687    /// If the year is zero, the sign of the century is not stored. To differentiate between
688    /// positive and negative zero, use `iso_year_century_is_negative`.
689    #[inline]
690    pub const fn iso_year_century(&self) -> Option<i16> {
691        self.iso_year_century.get_primitive()
692    }
693
694    /// Obtain the `iso_year_century_is_negative` component.
695    ///
696    /// This indicates whether the value returned from `iso_year_century` is negative. If the year
697    /// is zero, it is necessary to call this method for disambiguation.
698    #[inline]
699    pub const fn iso_year_century_is_negative(&self) -> Option<bool> {
700        match self.iso_year_century() {
701            Some(_) => Some(self.iso_year_century_is_negative),
702            None => None,
703        }
704    }
705
706    /// Obtain the `iso_year_last_two` component.
707    #[inline]
708    pub const fn iso_year_last_two(&self) -> Option<u8> {
709        self.iso_year_last_two.get_primitive()
710    }
711
712    /// Obtain the `month` component.
713    #[inline]
714    pub const fn month(&self) -> Option<Month> {
715        self.month
716    }
717
718    /// Obtain the `sunday_week_number` component.
719    #[inline]
720    pub const fn sunday_week_number(&self) -> Option<u8> {
721        self.sunday_week_number.get_primitive()
722    }
723
724    /// Obtain the `monday_week_number` component.
725    #[inline]
726    pub const fn monday_week_number(&self) -> Option<u8> {
727        self.monday_week_number.get_primitive()
728    }
729
730    /// Obtain the `iso_week_number` component.
731    #[inline]
732    pub const fn iso_week_number(&self) -> Option<NonZero<u8>> {
733        NonZero::new(const_try_opt!(self.iso_week_number.get_primitive()))
734    }
735
736    /// Obtain the `weekday` component.
737    #[inline]
738    pub const fn weekday(&self) -> Option<Weekday> {
739        self.weekday
740    }
741
742    /// Obtain the `ordinal` component.
743    #[inline]
744    pub const fn ordinal(&self) -> Option<NonZero<u16>> {
745        NonZero::new(const_try_opt!(self.ordinal.get_primitive()))
746    }
747
748    /// Obtain the `day` component.
749    #[inline]
750    pub const fn day(&self) -> Option<NonZero<u8>> {
751        NonZero::new(const_try_opt!(self.day.get_primitive()))
752    }
753
754    /// Obtain the `hour_24` component.
755    #[inline]
756    pub const fn hour_24(&self) -> Option<u8> {
757        self.hour_24.get_primitive()
758    }
759
760    /// Obtain the `hour_12` component.
761    #[inline]
762    pub const fn hour_12(&self) -> Option<NonZero<u8>> {
763        NonZero::new(const_try_opt!(self.hour_12.get_primitive()))
764    }
765
766    /// Obtain the `hour_12_is_pm` component.
767    #[inline]
768    pub const fn hour_12_is_pm(&self) -> Option<bool> {
769        self.hour_12_is_pm
770    }
771
772    /// Obtain the `minute` component.
773    #[inline]
774    pub const fn minute(&self) -> Option<u8> {
775        self.minute.get_primitive()
776    }
777
778    /// Obtain the `second` component.
779    #[inline]
780    pub const fn second(&self) -> Option<u8> {
781        self.second.get_primitive()
782    }
783
784    /// Obtain the `subsecond` component.
785    #[inline]
786    pub const fn subsecond(&self) -> Option<u32> {
787        self.subsecond.get_primitive()
788    }
789
790    /// Obtain the `offset_hour` component.
791    #[inline]
792    pub const fn offset_hour(&self) -> Option<i8> {
793        self.offset_hour.get_primitive()
794    }
795
796    /// Obtain the absolute value of the `offset_minute` component.
797    #[doc(hidden)]
798    #[deprecated(since = "0.3.8", note = "use `parsed.offset_minute_signed()` instead")]
799    #[inline]
800    pub const fn offset_minute(&self) -> Option<u8> {
801        Some(const_try_opt!(self.offset_minute_signed()).unsigned_abs())
802    }
803
804    /// Obtain the `offset_minute` component.
805    #[inline]
806    pub const fn offset_minute_signed(&self) -> Option<i8> {
807        match (self.offset_minute.get_primitive(), self.offset_is_negative) {
808            (Some(offset_minute), true) => Some(-offset_minute),
809            (Some(offset_minute), _) => Some(offset_minute),
810            (None, _) => None,
811        }
812    }
813
814    /// Obtain the absolute value of the `offset_second` component.
815    #[doc(hidden)]
816    #[deprecated(since = "0.3.8", note = "use `parsed.offset_second_signed()` instead")]
817    #[inline]
818    pub const fn offset_second(&self) -> Option<u8> {
819        Some(const_try_opt!(self.offset_second_signed()).unsigned_abs())
820    }
821
822    /// Obtain the `offset_second` component.
823    #[inline]
824    pub const fn offset_second_signed(&self) -> Option<i8> {
825        match (self.offset_second.get_primitive(), self.offset_is_negative) {
826            (Some(offset_second), true) => Some(-offset_second),
827            (Some(offset_second), _) => Some(offset_second),
828            (None, _) => None,
829        }
830    }
831
832    /// Obtain the `unix_timestamp_nanos` component.
833    #[inline]
834    pub const fn unix_timestamp_nanos(&self) -> Option<i128> {
835        self.unix_timestamp_nanos.get_primitive()
836    }
837}
838
839/// Generate setters based on the builders.
840macro_rules! setters {
841    ($($name:ident $setter:ident $builder:ident $type:ty;)*) => {$(
842        #[doc = concat!("Set the `", stringify!($name), "` component.")]
843        #[inline]
844        pub const fn $setter(&mut self, value: $type) -> Option<()> {
845            match self.$builder(value) {
846                Some(value) => {
847                    *self = value;
848                    Some(())
849                },
850                None => None,
851            }
852        }
853    )*};
854}
855
856/// Setter methods
857///
858/// All setters return `Option<()>`, which is `Some` if the value was set, and `None` if not. The
859/// setters _may_ fail if the value is invalid, though behavior is not guaranteed.
860impl Parsed {
861    setters! {
862        year set_year with_year i32;
863    }
864
865    /// Set the `year_century` component.
866    ///
867    /// If the value is zero, the sign of the century is taken from the second parameter. Otherwise
868    /// the sign is inferred from the value.
869    #[inline]
870    pub const fn set_year_century(&mut self, value: i16, is_negative: bool) -> Option<()> {
871        self.year_century = Option_ri16::Some(const_try_opt!(ri16::new(value)));
872        if value != 0 {
873            self.year_century_is_negative = value.is_negative();
874        } else {
875            self.year_century_is_negative = is_negative;
876        }
877        Some(())
878    }
879
880    setters! {
881        year_last_two set_year_last_two with_year_last_two u8;
882        iso_year set_iso_year with_iso_year i32;
883        iso_year_last_two set_iso_year_last_two with_iso_year_last_two u8;
884    }
885
886    /// Set the `iso_year_century` component.
887    ///
888    /// If the value is zero, the sign of the century is taken from the second parameter. Otherwise
889    /// the sign is inferred from the value.
890    #[inline]
891    pub const fn set_iso_year_century(&mut self, value: i16, is_negative: bool) -> Option<()> {
892        self.iso_year_century = Option_ri16::Some(const_try_opt!(ri16::new(value)));
893        if value != 0 {
894            self.iso_year_century_is_negative = value.is_negative();
895        } else {
896            self.iso_year_century_is_negative = is_negative;
897        }
898        Some(())
899    }
900
901    setters! {
902        month set_month with_month Month;
903        sunday_week_number set_sunday_week_number with_sunday_week_number u8;
904        monday_week_number set_monday_week_number with_monday_week_number u8;
905        iso_week_number set_iso_week_number with_iso_week_number NonZero<u8>;
906        weekday set_weekday with_weekday Weekday;
907        ordinal set_ordinal with_ordinal NonZero<u16>;
908        day set_day with_day NonZero<u8>;
909        hour_24 set_hour_24 with_hour_24 u8;
910        hour_12 set_hour_12 with_hour_12 NonZero<u8>;
911        hour_12_is_pm set_hour_12_is_pm with_hour_12_is_pm bool;
912        minute set_minute with_minute u8;
913        second set_second with_second u8;
914        subsecond set_subsecond with_subsecond u32;
915        offset_hour set_offset_hour with_offset_hour i8;
916        offset_minute set_offset_minute_signed with_offset_minute_signed i8;
917        offset_second set_offset_second_signed with_offset_second_signed i8;
918        unix_timestamp_nanos set_unix_timestamp_nanos with_unix_timestamp_nanos i128;
919    }
920
921    /// Set the `offset_minute` component.
922    #[doc(hidden)]
923    #[deprecated(
924        since = "0.3.8",
925        note = "use `parsed.set_offset_minute_signed()` instead"
926    )]
927    #[inline]
928    pub const fn set_offset_minute(&mut self, value: u8) -> Option<()> {
929        if value > i8::MAX.cast_unsigned() {
930            None
931        } else {
932            self.set_offset_minute_signed(value.cast_signed())
933        }
934    }
935
936    /// Set the `offset_minute` component.
937    #[doc(hidden)]
938    #[deprecated(
939        since = "0.3.8",
940        note = "use `parsed.set_offset_second_signed()` instead"
941    )]
942    #[inline]
943    pub const fn set_offset_second(&mut self, value: u8) -> Option<()> {
944        if value > i8::MAX.cast_unsigned() {
945            None
946        } else {
947            self.set_offset_second_signed(value.cast_signed())
948        }
949    }
950}
951
952/// Builder methods
953///
954/// All builder methods return `Option<Self>`, which is `Some` if the value was set, and `None` if
955/// not. The builder methods _may_ fail if the value is invalid, though behavior is not guaranteed.
956impl Parsed {
957    /// Set the `year` component and return `self`.
958    #[inline]
959    pub const fn with_year(mut self, value: i32) -> Option<Self> {
960        self.year = Option_ri32::Some(const_try_opt!(ri32::new(value)));
961        Some(self)
962    }
963
964    /// Set the `year_century` component and return `self`.
965    ///
966    /// If the value is zero, the sign of the century is taken from the second parameter. Otherwise
967    /// the sign is inferred from the value.
968    #[inline]
969    pub const fn with_year_century(mut self, value: i16, is_negative: bool) -> Option<Self> {
970        self.year_century = Option_ri16::Some(const_try_opt!(ri16::new(value)));
971        if value != 0 {
972            self.year_century_is_negative = value.is_negative();
973        } else {
974            self.year_century_is_negative = is_negative;
975        }
976        Some(self)
977    }
978
979    /// Set the `year_last_two` component and return `self`.
980    #[inline]
981    pub const fn with_year_last_two(mut self, value: u8) -> Option<Self> {
982        self.year_last_two = Option_ru8::Some(const_try_opt!(ru8::new(value)));
983        Some(self)
984    }
985
986    /// Set the `iso_year` component and return `self`.
987    #[inline]
988    pub const fn with_iso_year(mut self, value: i32) -> Option<Self> {
989        self.iso_year = Option_ri32::Some(const_try_opt!(ri32::new(value)));
990        Some(self)
991    }
992
993    /// Set the `iso_year_century` component and return `self`.
994    ///
995    /// If the value is zero, the sign of the century is taken from the second parameter. Otherwise
996    /// the sign is inferred from the value.
997    #[inline]
998    pub const fn with_iso_year_century(mut self, value: i16, is_negative: bool) -> Option<Self> {
999        self.iso_year_century = Option_ri16::Some(const_try_opt!(ri16::new(value)));
1000        if value != 0 {
1001            self.iso_year_century_is_negative = value.is_negative();
1002        } else {
1003            self.iso_year_century_is_negative = is_negative;
1004        }
1005        Some(self)
1006    }
1007
1008    /// Set the `iso_year_last_two` component and return `self`.
1009    #[inline]
1010    pub const fn with_iso_year_last_two(mut self, value: u8) -> Option<Self> {
1011        self.iso_year_last_two = Option_ru8::Some(const_try_opt!(ru8::new(value)));
1012        Some(self)
1013    }
1014
1015    /// Set the `month` component and return `self`.
1016    #[inline]
1017    pub const fn with_month(mut self, value: Month) -> Option<Self> {
1018        self.month = Some(value);
1019        Some(self)
1020    }
1021
1022    /// Set the `sunday_week_number` component and return `self`.
1023    #[inline]
1024    pub const fn with_sunday_week_number(mut self, value: u8) -> Option<Self> {
1025        self.sunday_week_number = Option_ru8::Some(const_try_opt!(ru8::new(value)));
1026        Some(self)
1027    }
1028
1029    /// Set the `monday_week_number` component and return `self`.
1030    #[inline]
1031    pub const fn with_monday_week_number(mut self, value: u8) -> Option<Self> {
1032        self.monday_week_number = Option_ru8::Some(const_try_opt!(ru8::new(value)));
1033        Some(self)
1034    }
1035
1036    /// Set the `iso_week_number` component and return `self`.
1037    #[inline]
1038    pub const fn with_iso_week_number(mut self, value: NonZero<u8>) -> Option<Self> {
1039        self.iso_week_number = Option_ru8::Some(const_try_opt!(ru8::new(value.get())));
1040        Some(self)
1041    }
1042
1043    /// Set the `weekday` component and return `self`.
1044    #[inline]
1045    pub const fn with_weekday(mut self, value: Weekday) -> Option<Self> {
1046        self.weekday = Some(value);
1047        Some(self)
1048    }
1049
1050    /// Set the `ordinal` component and return `self`.
1051    #[inline]
1052    pub const fn with_ordinal(mut self, value: NonZero<u16>) -> Option<Self> {
1053        self.ordinal = Option_ru16::Some(const_try_opt!(ru16::new(value.get())));
1054        Some(self)
1055    }
1056
1057    /// Set the `day` component and return `self`.
1058    #[inline]
1059    pub const fn with_day(mut self, value: NonZero<u8>) -> Option<Self> {
1060        self.day = Option_ru8::Some(const_try_opt!(ru8::new(value.get())));
1061        Some(self)
1062    }
1063
1064    /// Set the `hour_24` component and return `self`.
1065    #[inline]
1066    pub const fn with_hour_24(mut self, value: u8) -> Option<Self> {
1067        self.hour_24 = Option_ru8::Some(const_try_opt!(ru8::new(value)));
1068        Some(self)
1069    }
1070
1071    /// Set the `hour_12` component and return `self`.
1072    #[inline]
1073    pub const fn with_hour_12(mut self, value: NonZero<u8>) -> Option<Self> {
1074        self.hour_12 = Option_ru8::Some(const_try_opt!(ru8::new(value.get())));
1075        Some(self)
1076    }
1077
1078    /// Set the `hour_12_is_pm` component and return `self`.
1079    #[inline]
1080    pub const fn with_hour_12_is_pm(mut self, value: bool) -> Option<Self> {
1081        self.hour_12_is_pm = Some(value);
1082        Some(self)
1083    }
1084
1085    /// Set the `minute` component and return `self`.
1086    #[inline]
1087    pub const fn with_minute(mut self, value: u8) -> Option<Self> {
1088        self.minute = Option_ru8::Some(const_try_opt!(ru8::new(value)));
1089        Some(self)
1090    }
1091
1092    /// Set the `second` component and return `self`.
1093    #[inline]
1094    pub const fn with_second(mut self, value: u8) -> Option<Self> {
1095        self.second = Option_ru8::Some(const_try_opt!(ru8::new(value)));
1096        Some(self)
1097    }
1098
1099    /// Set the `subsecond` component and return `self`.
1100    #[inline]
1101    pub const fn with_subsecond(mut self, value: u32) -> Option<Self> {
1102        self.subsecond = Option_ru32::Some(const_try_opt!(ru32::new(value)));
1103        Some(self)
1104    }
1105
1106    /// Set the `offset_hour` component and return `self`.
1107    #[inline]
1108    pub const fn with_offset_hour(mut self, value: i8) -> Option<Self> {
1109        self.offset_hour = Option_ri8::Some(const_try_opt!(ri8::new(value)));
1110        Some(self)
1111    }
1112
1113    /// Set the `offset_minute` component and return `self`.
1114    #[doc(hidden)]
1115    #[deprecated(
1116        since = "0.3.8",
1117        note = "use `parsed.with_offset_minute_signed()` instead"
1118    )]
1119    #[inline]
1120    pub const fn with_offset_minute(self, value: u8) -> Option<Self> {
1121        if value > i8::MAX.cast_unsigned() {
1122            None
1123        } else {
1124            self.with_offset_minute_signed(value.cast_signed())
1125        }
1126    }
1127
1128    /// Set the `offset_minute` component and return `self`.
1129    #[inline]
1130    pub const fn with_offset_minute_signed(mut self, value: i8) -> Option<Self> {
1131        self.offset_minute = Option_ri8::Some(const_try_opt!(ri8::new(value)));
1132        Some(self)
1133    }
1134
1135    /// Set the `offset_minute` component and return `self`.
1136    #[doc(hidden)]
1137    #[deprecated(
1138        since = "0.3.8",
1139        note = "use `parsed.with_offset_second_signed()` instead"
1140    )]
1141    #[inline]
1142    pub const fn with_offset_second(self, value: u8) -> Option<Self> {
1143        if value > i8::MAX.cast_unsigned() {
1144            None
1145        } else {
1146            self.with_offset_second_signed(value.cast_signed())
1147        }
1148    }
1149
1150    /// Set the `offset_second` component and return `self`.
1151    #[inline]
1152    pub const fn with_offset_second_signed(mut self, value: i8) -> Option<Self> {
1153        self.offset_second = Option_ri8::Some(const_try_opt!(ri8::new(value)));
1154        Some(self)
1155    }
1156
1157    /// Set the `unix_timestamp_nanos` component and return `self`.
1158    #[inline]
1159    pub const fn with_unix_timestamp_nanos(mut self, value: i128) -> Option<Self> {
1160        self.unix_timestamp_nanos = Option_ri128::Some(const_try_opt!(ri128::new(value)));
1161        Some(self)
1162    }
1163}
1164
1165impl TryFrom<Parsed> for Date {
1166    type Error = error::TryFromParsed;
1167
1168    #[inline]
1169    fn try_from(mut parsed: Parsed) -> Result<Self, Self::Error> {
1170        /// Match on the components that need to be present.
1171        macro_rules! match_ {
1172            (_ => $catch_all:expr $(,)?) => {
1173                $catch_all
1174            };
1175            (($($name:ident),* $(,)?) => $arm:expr, $($rest:tt)*) => {
1176                if let ($(Some($name)),*) = ($(parsed.$name()),*) {
1177                    $arm
1178                } else {
1179                    match_!($($rest)*)
1180                }
1181            };
1182        }
1183
1184        /// Get the value needed to adjust the ordinal day for Sunday and Monday-based week
1185        /// numbering.
1186        #[inline]
1187        const fn adjustment(year: i32) -> i16 {
1188            // Safety: `ordinal` is not zero.
1189            match unsafe { Date::__from_ordinal_date_unchecked(year, 1) }.weekday() {
1190                Weekday::Monday => 7,
1191                Weekday::Tuesday => 1,
1192                Weekday::Wednesday => 2,
1193                Weekday::Thursday => 3,
1194                Weekday::Friday => 4,
1195                Weekday::Saturday => 5,
1196                Weekday::Sunday => 6,
1197            }
1198        }
1199
1200        // If we do not have the year but we have *both* the century and the last two digits, we can
1201        // construct the year. Likewise for the ISO year.
1202        if let (None, Some(century), Some(is_negative), Some(last_two)) = (
1203            parsed.year(),
1204            parsed.year_century(),
1205            parsed.year_century_is_negative(),
1206            parsed.year_last_two(),
1207        ) {
1208            let year = if is_negative {
1209                100 * century.extend::<i32>() - last_two.cast_signed().extend::<i32>()
1210            } else {
1211                100 * century.extend::<i32>() + last_two.cast_signed().extend::<i32>()
1212            };
1213            parsed.year = Option_ri32::from(ri32::new(year));
1214        }
1215        if let (None, Some(century), Some(is_negative), Some(last_two)) = (
1216            parsed.iso_year(),
1217            parsed.iso_year_century(),
1218            parsed.iso_year_century_is_negative(),
1219            parsed.iso_year_last_two(),
1220        ) {
1221            let iso_year = if is_negative {
1222                100 * century.extend::<i32>() - last_two.cast_signed().extend::<i32>()
1223            } else {
1224                100 * century.extend::<i32>() + last_two.cast_signed().extend::<i32>()
1225            };
1226            parsed.iso_year = Option_ri32::from(ri32::new(iso_year));
1227        }
1228
1229        match_! {
1230            (year, ordinal) => Ok(Self::from_ordinal_date(year, ordinal.get())?),
1231            (year, month, day) => Ok(Self::from_calendar_date(year, month, day.get())?),
1232            (iso_year, iso_week_number, weekday) => Ok(Self::from_iso_week_date(
1233                iso_year,
1234                iso_week_number.get(),
1235                weekday,
1236            )?),
1237            (year, sunday_week_number, weekday) => Ok(Self::from_ordinal_date(
1238                year,
1239                (sunday_week_number.cast_signed().extend::<i16>() * 7
1240                    + weekday.number_days_from_sunday().cast_signed().extend::<i16>()
1241                    - adjustment(year)
1242                    + 1).cast_unsigned(),
1243            )?),
1244            (year, monday_week_number, weekday) => Ok(Self::from_ordinal_date(
1245                year,
1246                (monday_week_number.cast_signed().extend::<i16>() * 7
1247                    + weekday.number_days_from_monday().cast_signed().extend::<i16>()
1248                    - adjustment(year)
1249                    + 1).cast_unsigned(),
1250            )?),
1251            _ => Err(InsufficientInformation),
1252        }
1253    }
1254}
1255
1256impl TryFrom<Parsed> for Time {
1257    type Error = error::TryFromParsed;
1258
1259    #[inline]
1260    fn try_from(parsed: Parsed) -> Result<Self, Self::Error> {
1261        let hour = match (parsed.hour_24(), parsed.hour_12(), parsed.hour_12_is_pm()) {
1262            (Some(hour), _, _) => hour,
1263            (_, Some(hour), Some(false)) if hour.get() == 12 => 0,
1264            (_, Some(hour), Some(true)) if hour.get() == 12 => 12,
1265            (_, Some(hour), Some(false)) => hour.get(),
1266            (_, Some(hour), Some(true)) => hour.get() + 12,
1267            _ => return Err(InsufficientInformation),
1268        };
1269
1270        if parsed.hour_24().is_none()
1271            && parsed.hour_12().is_some()
1272            && parsed.hour_12_is_pm().is_some()
1273            && parsed.minute().is_none()
1274            && parsed.second().is_none()
1275            && parsed.subsecond().is_none()
1276        {
1277            return Ok(Self::from_hms_nano(hour, 0, 0, 0)?);
1278        }
1279
1280        // Reject combinations such as hour-second with minute omitted.
1281        match (parsed.minute(), parsed.second(), parsed.subsecond()) {
1282            (None, None, None) => Ok(Self::from_hms_nano(hour, 0, 0, 0)?),
1283            (Some(minute), None, None) => Ok(Self::from_hms_nano(hour, minute, 0, 0)?),
1284            (Some(minute), Some(second), None) => Ok(Self::from_hms_nano(hour, minute, second, 0)?),
1285            (Some(minute), Some(second), Some(subsecond)) => {
1286                Ok(Self::from_hms_nano(hour, minute, second, subsecond)?)
1287            }
1288            _ => Err(InsufficientInformation),
1289        }
1290    }
1291}
1292
1293#[inline]
1294fn utc_offset_try_from_parsed<const REQUIRED: bool>(
1295    parsed: Parsed,
1296) -> Result<UtcOffset, error::TryFromParsed> {
1297    let hour = match (REQUIRED, parsed.offset_hour()) {
1298        // An offset is required, but the hour is missing. Return an error.
1299        (true, None) => return Err(InsufficientInformation),
1300        // An offset is not required (e.g. for `UtcDateTime`). As the hour is missing, minutes and
1301        // seconds are not parsed. This is UTC.
1302        (false, None) => return Ok(UtcOffset::UTC),
1303        // Any other situation has an hour present.
1304        (_, Some(hour)) => hour,
1305    };
1306    let minute = parsed.offset_minute_signed();
1307    // Force `second` to be `None` if `minute` is `None`.
1308    let second = minute.and_then(|_| parsed.offset_second_signed());
1309
1310    let minute = minute.unwrap_or(0);
1311    let second = second.unwrap_or(0);
1312
1313    UtcOffset::from_hms(hour, minute, second).map_err(Into::into)
1314}
1315
1316impl TryFrom<Parsed> for UtcOffset {
1317    type Error = error::TryFromParsed;
1318
1319    #[inline]
1320    fn try_from(parsed: Parsed) -> Result<Self, Self::Error> {
1321        utc_offset_try_from_parsed::<true>(parsed)
1322    }
1323}
1324
1325impl TryFrom<Parsed> for PrimitiveDateTime {
1326    type Error = error::TryFromParsed;
1327
1328    #[inline]
1329    fn try_from(parsed: Parsed) -> Result<Self, Self::Error> {
1330        Ok(Self::new(parsed.try_into()?, parsed.try_into()?))
1331    }
1332}
1333
1334impl TryFrom<Parsed> for UtcDateTime {
1335    type Error = error::TryFromParsed;
1336
1337    #[inline]
1338    fn try_from(mut parsed: Parsed) -> Result<Self, Self::Error> {
1339        if let Some(timestamp) = parsed.unix_timestamp_nanos() {
1340            let mut value = Self::from_unix_timestamp_nanos(timestamp)?;
1341            if let Some(subsecond) = parsed.subsecond() {
1342                value = value.replace_nanosecond(subsecond)?;
1343            }
1344            return Ok(value);
1345        }
1346
1347        // Some well-known formats explicitly allow leap seconds. We don't currently support them,
1348        // so treat it as the nearest preceding moment that can be represented. Because leap seconds
1349        // always fall at the end of a month UTC, reject any that are at other times.
1350        let leap_second_input = if parsed.leap_second_allowed && parsed.second() == Some(60) {
1351            if parsed.set_second(59).is_none() {
1352                bug!("59 is a valid second");
1353            }
1354            if parsed.set_subsecond(999_999_999).is_none() {
1355                bug!("999_999_999 is a valid subsecond");
1356            }
1357            true
1358        } else {
1359            false
1360        };
1361
1362        let dt = OffsetDateTime::new_in_offset(
1363            Date::try_from(parsed)?,
1364            Time::try_from(parsed)?,
1365            utc_offset_try_from_parsed::<false>(parsed)?,
1366        )
1367        .to_utc();
1368
1369        if leap_second_input && !dt.is_valid_leap_second_stand_in() {
1370            return Err(error::TryFromParsed::ComponentRange(
1371                error::ComponentRange::conditional("second"),
1372            ));
1373        }
1374        Ok(dt)
1375    }
1376}
1377
1378impl TryFrom<Parsed> for OffsetDateTime {
1379    type Error = error::TryFromParsed;
1380
1381    #[inline]
1382    fn try_from(mut parsed: Parsed) -> Result<Self, Self::Error> {
1383        if let Some(timestamp) = parsed.unix_timestamp_nanos() {
1384            let mut value = Self::from_unix_timestamp_nanos(timestamp)?;
1385            if let Some(subsecond) = parsed.subsecond() {
1386                value = value.replace_nanosecond(subsecond)?;
1387            }
1388            return Ok(value);
1389        }
1390
1391        // Some well-known formats explicitly allow leap seconds. We don't currently support them,
1392        // so treat it as the nearest preceding moment that can be represented. Because leap seconds
1393        // always fall at the end of a month UTC, reject any that are at other times.
1394        let leap_second_input = if parsed.leap_second_allowed && parsed.second() == Some(60) {
1395            if parsed.set_second(59).is_none() {
1396                bug!("59 is a valid second");
1397            }
1398            if parsed.set_subsecond(999_999_999).is_none() {
1399                bug!("999_999_999 is a valid subsecond");
1400            }
1401            true
1402        } else {
1403            false
1404        };
1405
1406        let dt = Self::new_in_offset(
1407            Date::try_from(parsed)?,
1408            Time::try_from(parsed)?,
1409            UtcOffset::try_from(parsed)?,
1410        );
1411
1412        if leap_second_input && !dt.is_valid_leap_second_stand_in() {
1413            return Err(error::TryFromParsed::ComponentRange(
1414                error::ComponentRange::conditional("second"),
1415            ));
1416        }
1417        Ok(dt)
1418    }
1419}