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