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