Coverage Report

Created: 2026-01-17 07:03

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