Coverage Report

Created: 2026-02-14 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/time-0.3.13/src/parsing/parsed.rs
Line
Count
Source
1
//! Information parsed from an input and format description.
2
3
use core::num::{NonZeroU16, NonZeroU8};
4
5
use crate::error::TryFromParsed::InsufficientInformation;
6
use crate::format_description::modifier::{WeekNumberRepr, YearRepr};
7
use crate::format_description::{Component, FormatItem};
8
use crate::parsing::component::{
9
    parse_day, parse_hour, parse_minute, parse_month, parse_offset_hour, parse_offset_minute,
10
    parse_offset_second, parse_ordinal, parse_period, parse_second, parse_subsecond,
11
    parse_week_number, parse_weekday, parse_year, Period,
12
};
13
use crate::parsing::ParsedItem;
14
use crate::{error, Date, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcOffset, Weekday};
15
16
/// All information parsed.
17
///
18
/// This information is directly used to construct the final values.
19
///
20
/// Most users will not need think about this struct in any way. It is public to allow for manual
21
/// control over values, in the instance that the default parser is insufficient.
22
#[derive(Debug, Clone, Copy)]
23
pub struct Parsed {
24
    /// Calendar year.
25
    year: Option<i32>,
26
    /// The last two digits of the calendar year.
27
    year_last_two: Option<u8>,
28
    /// Year of the [ISO week date](https://en.wikipedia.org/wiki/ISO_week_date).
29
    iso_year: Option<i32>,
30
    /// The last two digits of the ISO week year.
31
    iso_year_last_two: Option<u8>,
32
    /// Month of the year.
33
    month: Option<Month>,
34
    /// Week of the year, where week one begins on the first Sunday of the calendar year.
35
    sunday_week_number: Option<u8>,
36
    /// Week of the year, where week one begins on the first Monday of the calendar year.
37
    monday_week_number: Option<u8>,
38
    /// Week of the year, where week one is the Monday-to-Sunday period containing January 4.
39
    iso_week_number: Option<NonZeroU8>,
40
    /// Day of the week.
41
    weekday: Option<Weekday>,
42
    /// Day of the year.
43
    ordinal: Option<NonZeroU16>,
44
    /// Day of the month.
45
    day: Option<NonZeroU8>,
46
    /// Hour within the day.
47
    hour_24: Option<u8>,
48
    /// Hour within the 12-hour period (midnight to noon or vice versa). This is typically used in
49
    /// conjunction with AM/PM, which is indicated by the `hour_12_is_pm` field.
50
    hour_12: Option<NonZeroU8>,
51
    /// Whether the `hour_12` field indicates a time that "PM".
52
    hour_12_is_pm: Option<bool>,
53
    /// Minute within the hour.
54
    minute: Option<u8>,
55
    /// Second within the minute.
56
    second: Option<u8>,
57
    /// Nanosecond within the second.
58
    subsecond: Option<u32>,
59
    /// Whole hours of the UTC offset.
60
    offset_hour: Option<i8>,
61
    /// Minutes within the hour of the UTC offset.
62
    offset_minute: Option<i8>,
63
    /// Seconds within the minute of the UTC offset.
64
    offset_second: Option<i8>,
65
    /// Indicates whether a leap second is permitted to be parsed. This is required by some
66
    /// well-known formats.
67
    leap_second_allowed: bool,
68
}
69
70
impl Parsed {
71
    /// Create a new instance of `Parsed` with no information known.
72
0
    pub const fn new() -> Self {
73
0
        Self {
74
0
            year: None,
75
0
            year_last_two: None,
76
0
            iso_year: None,
77
0
            iso_year_last_two: None,
78
0
            month: None,
79
0
            sunday_week_number: None,
80
0
            monday_week_number: None,
81
0
            iso_week_number: None,
82
0
            weekday: None,
83
0
            ordinal: None,
84
0
            day: None,
85
0
            hour_24: None,
86
0
            hour_12: None,
87
0
            hour_12_is_pm: None,
88
0
            minute: None,
89
0
            second: None,
90
0
            subsecond: None,
91
0
            offset_hour: None,
92
0
            offset_minute: None,
93
0
            offset_second: None,
94
0
            leap_second_allowed: false,
95
0
        }
96
0
    }
97
98
    /// Parse a single [`FormatItem`], mutating the struct. The remaining input is returned as the
99
    /// `Ok` value.
100
    ///
101
    /// If a [`FormatItem::Optional`] is passed, parsing will not fail; the input will be returned
102
    /// as-is if the expected format is not present.
103
0
    pub fn parse_item<'a>(
104
0
        &mut self,
105
0
        input: &'a [u8],
106
0
        item: &FormatItem<'_>,
107
0
    ) -> Result<&'a [u8], error::ParseFromDescription> {
108
0
        match item {
109
0
            FormatItem::Literal(literal) => Self::parse_literal(input, literal),
110
0
            FormatItem::Component(component) => self.parse_component(input, *component),
111
0
            FormatItem::Compound(compound) => self.parse_items(input, compound),
112
0
            FormatItem::Optional(item) => self.parse_item(input, item).or(Ok(input)),
113
0
            FormatItem::First(items) => {
114
0
                let mut first_err = None;
115
116
0
                for item in items.iter() {
117
0
                    match self.parse_item(input, item) {
118
0
                        Ok(remaining_input) => return Ok(remaining_input),
119
0
                        Err(err) if first_err.is_none() => first_err = Some(err),
120
0
                        Err(_) => {}
121
                    }
122
                }
123
124
0
                match first_err {
125
0
                    Some(err) => Err(err),
126
                    // This location will be reached if the slice is empty, skipping the `for` loop.
127
                    // As this case is expected to be uncommon, there's no need to check up front.
128
0
                    None => Ok(input),
129
                }
130
            }
131
        }
132
0
    }
133
134
    /// Parse a sequence of [`FormatItem`]s, mutating the struct. The remaining input is returned as
135
    /// the `Ok` value.
136
    ///
137
    /// This method will fail if any of the contained [`FormatItem`]s fail to parse. `self` will not
138
    /// be mutated in this instance.
139
0
    pub fn parse_items<'a>(
140
0
        &mut self,
141
0
        mut input: &'a [u8],
142
0
        items: &[FormatItem<'_>],
143
0
    ) -> Result<&'a [u8], error::ParseFromDescription> {
144
        // Make a copy that we can mutate. It will only be set to the user's copy if everything
145
        // succeeds.
146
0
        let mut this = *self;
147
0
        for item in items {
148
0
            input = this.parse_item(input, item)?;
149
        }
150
0
        *self = this;
151
0
        Ok(input)
152
0
    }
153
154
    /// Parse a literal byte sequence. The remaining input is returned as the `Ok` value.
155
0
    pub fn parse_literal<'a>(
156
0
        input: &'a [u8],
157
0
        literal: &[u8],
158
0
    ) -> Result<&'a [u8], error::ParseFromDescription> {
159
0
        input
160
0
            .strip_prefix(literal)
161
0
            .ok_or(error::ParseFromDescription::InvalidLiteral)
162
0
    }
163
164
    /// Parse a single component, mutating the struct. The remaining input is returned as the `Ok`
165
    /// value.
166
0
    pub fn parse_component<'a>(
167
0
        &mut self,
168
0
        input: &'a [u8],
169
0
        component: Component,
170
0
    ) -> Result<&'a [u8], error::ParseFromDescription> {
171
        use error::ParseFromDescription::InvalidComponent;
172
173
0
        match component {
174
0
            Component::Day(modifiers) => parse_day(input, modifiers)
175
0
                .and_then(|parsed| parsed.consume_value(|value| self.set_day(value)))
176
0
                .ok_or(InvalidComponent("day")),
177
0
            Component::Month(modifiers) => parse_month(input, modifiers)
178
0
                .and_then(|parsed| parsed.consume_value(|value| self.set_month(value)))
179
0
                .ok_or(InvalidComponent("month")),
180
0
            Component::Ordinal(modifiers) => parse_ordinal(input, modifiers)
181
0
                .and_then(|parsed| parsed.consume_value(|value| self.set_ordinal(value)))
182
0
                .ok_or(InvalidComponent("ordinal")),
183
0
            Component::Weekday(modifiers) => parse_weekday(input, modifiers)
184
0
                .and_then(|parsed| parsed.consume_value(|value| self.set_weekday(value)))
185
0
                .ok_or(InvalidComponent("weekday")),
186
0
            Component::WeekNumber(modifiers) => {
187
0
                let ParsedItem(remaining, value) =
188
0
                    parse_week_number(input, modifiers).ok_or(InvalidComponent("week number"))?;
189
0
                match modifiers.repr {
190
                    WeekNumberRepr::Iso => {
191
0
                        NonZeroU8::new(value).and_then(|value| self.set_iso_week_number(value))
192
                    }
193
0
                    WeekNumberRepr::Sunday => self.set_sunday_week_number(value),
194
0
                    WeekNumberRepr::Monday => self.set_monday_week_number(value),
195
                }
196
0
                .ok_or(InvalidComponent("week number"))?;
197
0
                Ok(remaining)
198
            }
199
0
            Component::Year(modifiers) => {
200
0
                let ParsedItem(remaining, value) =
201
0
                    parse_year(input, modifiers).ok_or(InvalidComponent("year"))?;
202
0
                match (modifiers.iso_week_based, modifiers.repr) {
203
0
                    (false, YearRepr::Full) => self.set_year(value),
204
0
                    (false, YearRepr::LastTwo) => self.set_year_last_two(value as _),
205
0
                    (true, YearRepr::Full) => self.set_iso_year(value),
206
0
                    (true, YearRepr::LastTwo) => self.set_iso_year_last_two(value as _),
207
                }
208
0
                .ok_or(InvalidComponent("year"))?;
209
0
                Ok(remaining)
210
            }
211
0
            Component::Hour(modifiers) => {
212
0
                let ParsedItem(remaining, value) =
213
0
                    parse_hour(input, modifiers).ok_or(InvalidComponent("hour"))?;
214
0
                if modifiers.is_12_hour_clock {
215
0
                    NonZeroU8::new(value).and_then(|value| self.set_hour_12(value))
216
                } else {
217
0
                    self.set_hour_24(value)
218
                }
219
0
                .ok_or(InvalidComponent("hour"))?;
220
0
                Ok(remaining)
221
            }
222
0
            Component::Minute(modifiers) => parse_minute(input, modifiers)
223
0
                .and_then(|parsed| parsed.consume_value(|value| self.set_minute(value)))
224
0
                .ok_or(InvalidComponent("minute")),
225
0
            Component::Period(modifiers) => parse_period(input, modifiers)
226
0
                .and_then(|parsed| {
227
0
                    parsed.consume_value(|value| self.set_hour_12_is_pm(value == Period::Pm))
228
0
                })
229
0
                .ok_or(InvalidComponent("period")),
230
0
            Component::Second(modifiers) => parse_second(input, modifiers)
231
0
                .and_then(|parsed| parsed.consume_value(|value| self.set_second(value)))
232
0
                .ok_or(InvalidComponent("second")),
233
0
            Component::Subsecond(modifiers) => parse_subsecond(input, modifiers)
234
0
                .and_then(|parsed| parsed.consume_value(|value| self.set_subsecond(value)))
235
0
                .ok_or(InvalidComponent("subsecond")),
236
0
            Component::OffsetHour(modifiers) => parse_offset_hour(input, modifiers)
237
0
                .and_then(|parsed| parsed.consume_value(|value| self.set_offset_hour(value)))
238
0
                .ok_or(InvalidComponent("offset hour")),
239
0
            Component::OffsetMinute(modifiers) => parse_offset_minute(input, modifiers)
240
0
                .and_then(|parsed| {
241
0
                    parsed.consume_value(|value| self.set_offset_minute_signed(value))
242
0
                })
243
0
                .ok_or(InvalidComponent("offset minute")),
244
0
            Component::OffsetSecond(modifiers) => parse_offset_second(input, modifiers)
245
0
                .and_then(|parsed| {
246
0
                    parsed.consume_value(|value| self.set_offset_second_signed(value))
247
0
                })
248
0
                .ok_or(InvalidComponent("offset second")),
249
        }
250
0
    }
251
}
252
253
/// Generate getters for each of the fields.
254
macro_rules! getters {
255
    ($($name:ident: $ty:ty),+ $(,)?) => {$(
256
        /// Obtain the named component.
257
0
        pub const fn $name(&self) -> Option<$ty> {
258
0
            self.$name
259
0
        }
Unexecuted instantiation: <time::parsing::parsed::Parsed>::iso_week_number
Unexecuted instantiation: <time::parsing::parsed::Parsed>::monday_week_number
Unexecuted instantiation: <time::parsing::parsed::Parsed>::sunday_week_number
Unexecuted instantiation: <time::parsing::parsed::Parsed>::day
Unexecuted instantiation: <time::parsing::parsed::Parsed>::year
Unexecuted instantiation: <time::parsing::parsed::Parsed>::month
Unexecuted instantiation: <time::parsing::parsed::Parsed>::ordinal
Unexecuted instantiation: <time::parsing::parsed::Parsed>::weekday
Unexecuted instantiation: <time::parsing::parsed::Parsed>::iso_year
Unexecuted instantiation: <time::parsing::parsed::Parsed>::offset_hour
Unexecuted instantiation: <time::parsing::parsed::Parsed>::second
Unexecuted instantiation: <time::parsing::parsed::Parsed>::year_last_two
Unexecuted instantiation: <time::parsing::parsed::Parsed>::iso_year_last_two
Unexecuted instantiation: <time::parsing::parsed::Parsed>::hour_12_is_pm
Unexecuted instantiation: <time::parsing::parsed::Parsed>::minute
Unexecuted instantiation: <time::parsing::parsed::Parsed>::hour_12
Unexecuted instantiation: <time::parsing::parsed::Parsed>::hour_24
Unexecuted instantiation: <time::parsing::parsed::Parsed>::subsecond
260
    )*}
261
}
262
263
/// Getter methods
264
impl Parsed {
265
    getters! {
266
        year: i32,
267
        year_last_two: u8,
268
        iso_year: i32,
269
        iso_year_last_two: u8,
270
        month: Month,
271
        sunday_week_number: u8,
272
        monday_week_number: u8,
273
        iso_week_number: NonZeroU8,
274
        weekday: Weekday,
275
        ordinal: NonZeroU16,
276
        day: NonZeroU8,
277
        hour_24: u8,
278
        hour_12: NonZeroU8,
279
        hour_12_is_pm: bool,
280
        minute: u8,
281
        second: u8,
282
        subsecond: u32,
283
        offset_hour: i8,
284
    }
285
286
    /// Obtain the absolute value of the offset minute.
287
    #[deprecated(since = "0.3.8", note = "use `parsed.offset_minute_signed()` instead")]
288
0
    pub const fn offset_minute(&self) -> Option<u8> {
289
0
        Some(const_try_opt!(self.offset_minute_signed()).unsigned_abs())
290
0
    }
291
292
    /// Obtain the offset minute as an `i8`.
293
0
    pub const fn offset_minute_signed(&self) -> Option<i8> {
294
0
        self.offset_minute
295
0
    }
296
297
    /// Obtain the absolute value of the offset second.
298
    #[deprecated(since = "0.3.8", note = "use `parsed.offset_second_signed()` instead")]
299
0
    pub const fn offset_second(&self) -> Option<u8> {
300
0
        Some(const_try_opt!(self.offset_second_signed()).unsigned_abs())
301
0
    }
302
303
    /// Obtain the offset second as an `i8`.
304
0
    pub const fn offset_second_signed(&self) -> Option<i8> {
305
0
        self.offset_second
306
0
    }
307
308
    /// Obtain whether leap seconds are permitted in the current format.
309
0
    pub(crate) const fn leap_second_allowed(&self) -> bool {
310
0
        self.leap_second_allowed
311
0
    }
312
}
313
314
/// Generate setters for each of the fields.
315
///
316
/// This macro should only be used for fields where the value is not validated beyond its type.
317
macro_rules! setters {
318
    ($($setter_name:ident $name:ident: $ty:ty),+ $(,)?) => {$(
319
        /// Set the named component.
320
0
        pub fn $setter_name(&mut self, value: $ty) -> Option<()> {
321
0
            self.$name = Some(value);
322
0
            Some(())
323
0
        }
Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_hour_12
Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_ordinal
Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_iso_year
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_second
Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_subsecond
Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_minute
Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_hour_24
Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_weekday
Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_offset_hour
Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_day
Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_year
Unexecuted instantiation: <time::parsing::parsed::Parsed>::set_month
324
    )*}
325
}
326
327
/// Setter methods
328
///
329
/// All setters return `Option<()>`, which is `Some` if the value was set, and `None` if not. The
330
/// setters _may_ fail if the value is invalid, though behavior is not guaranteed.
331
impl Parsed {
332
    setters! {
333
        set_year year: i32,
334
        set_year_last_two year_last_two: u8,
335
        set_iso_year iso_year: i32,
336
        set_iso_year_last_two iso_year_last_two: u8,
337
        set_month month: Month,
338
        set_sunday_week_number sunday_week_number: u8,
339
        set_monday_week_number monday_week_number: u8,
340
        set_iso_week_number iso_week_number: NonZeroU8,
341
        set_weekday weekday: Weekday,
342
        set_ordinal ordinal: NonZeroU16,
343
        set_day day: NonZeroU8,
344
        set_hour_24 hour_24: u8,
345
        set_hour_12 hour_12: NonZeroU8,
346
        set_hour_12_is_pm hour_12_is_pm: bool,
347
        set_minute minute: u8,
348
        set_second second: u8,
349
        set_subsecond subsecond: u32,
350
        set_offset_hour offset_hour: i8,
351
    }
352
353
    /// Set the named component.
354
    #[deprecated(
355
        since = "0.3.8",
356
        note = "use `parsed.set_offset_minute_signed()` instead"
357
    )]
358
0
    pub fn set_offset_minute(&mut self, value: u8) -> Option<()> {
359
0
        if value > i8::MAX as u8 {
360
0
            None
361
        } else {
362
0
            self.set_offset_minute_signed(value as _)
363
        }
364
0
    }
365
366
    /// Set the `offset_minute` component.
367
0
    pub fn set_offset_minute_signed(&mut self, value: i8) -> Option<()> {
368
0
        self.offset_minute = Some(value);
369
0
        Some(())
370
0
    }
371
372
    /// Set the named component.
373
    #[deprecated(
374
        since = "0.3.8",
375
        note = "use `parsed.set_offset_second_signed()` instead"
376
    )]
377
0
    pub fn set_offset_second(&mut self, value: u8) -> Option<()> {
378
0
        if value > i8::MAX as u8 {
379
0
            None
380
        } else {
381
0
            self.set_offset_second_signed(value as _)
382
        }
383
0
    }
384
385
    /// Set the `offset_second` component.
386
0
    pub fn set_offset_second_signed(&mut self, value: i8) -> Option<()> {
387
0
        self.offset_second = Some(value);
388
0
        Some(())
389
0
    }
390
391
    /// Set the leap second allowed flag.
392
0
    pub(crate) fn set_leap_second_allowed(&mut self, value: bool) {
393
0
        self.leap_second_allowed = value;
394
0
    }
395
}
396
397
/// Generate build methods for each of the fields.
398
///
399
/// This macro should only be used for fields where the value is not validated beyond its type.
400
macro_rules! builders {
401
    ($($builder_name:ident $name:ident: $ty:ty),+ $(,)?) => {$(
402
        /// Set the named component and return `self`.
403
0
        pub const fn $builder_name(mut self, value: $ty) -> Option<Self> {
404
0
            self.$name = Some(value);
405
0
            Some(self)
406
0
        }
Unexecuted instantiation: <time::parsing::parsed::Parsed>::with_month
Unexecuted instantiation: <time::parsing::parsed::Parsed>::with_minute
Unexecuted instantiation: <time::parsing::parsed::Parsed>::with_second
Unexecuted instantiation: <time::parsing::parsed::Parsed>::with_hour_12
Unexecuted instantiation: <time::parsing::parsed::Parsed>::with_hour_24
Unexecuted instantiation: <time::parsing::parsed::Parsed>::with_ordinal
Unexecuted instantiation: <time::parsing::parsed::Parsed>::with_weekday
Unexecuted instantiation: <time::parsing::parsed::Parsed>::with_iso_year
Unexecuted instantiation: <time::parsing::parsed::Parsed>::with_subsecond
Unexecuted instantiation: <time::parsing::parsed::Parsed>::with_offset_hour
Unexecuted instantiation: <time::parsing::parsed::Parsed>::with_hour_12_is_pm
Unexecuted instantiation: <time::parsing::parsed::Parsed>::with_year_last_two
Unexecuted instantiation: <time::parsing::parsed::Parsed>::with_iso_week_number
Unexecuted instantiation: <time::parsing::parsed::Parsed>::with_iso_year_last_two
Unexecuted instantiation: <time::parsing::parsed::Parsed>::with_monday_week_number
Unexecuted instantiation: <time::parsing::parsed::Parsed>::with_sunday_week_number
Unexecuted instantiation: <time::parsing::parsed::Parsed>::with_day
Unexecuted instantiation: <time::parsing::parsed::Parsed>::with_year
407
    )*}
408
}
409
410
/// Builder methods
411
///
412
/// All builder methods return `Option<Self>`, which is `Some` if the value was set, and `None` if
413
/// not. The builder methods _may_ fail if the value is invalid, though behavior is not guaranteed.
414
impl Parsed {
415
    builders! {
416
        with_year year: i32,
417
        with_year_last_two year_last_two: u8,
418
        with_iso_year iso_year: i32,
419
        with_iso_year_last_two iso_year_last_two: u8,
420
        with_month month: Month,
421
        with_sunday_week_number sunday_week_number: u8,
422
        with_monday_week_number monday_week_number: u8,
423
        with_iso_week_number iso_week_number: NonZeroU8,
424
        with_weekday weekday: Weekday,
425
        with_ordinal ordinal: NonZeroU16,
426
        with_day day: NonZeroU8,
427
        with_hour_24 hour_24: u8,
428
        with_hour_12 hour_12: NonZeroU8,
429
        with_hour_12_is_pm hour_12_is_pm: bool,
430
        with_minute minute: u8,
431
        with_second second: u8,
432
        with_subsecond subsecond: u32,
433
        with_offset_hour offset_hour: i8,
434
    }
435
436
    /// Set the named component and return `self`.
437
    #[deprecated(
438
        since = "0.3.8",
439
        note = "use `parsed.with_offset_minute_signed()` instead"
440
    )]
441
0
    pub const fn with_offset_minute(self, value: u8) -> Option<Self> {
442
0
        if value > i8::MAX as u8 {
443
0
            None
444
        } else {
445
0
            self.with_offset_minute_signed(value as _)
446
        }
447
0
    }
448
449
    /// Set the `offset_minute` component and return `self`.
450
0
    pub const fn with_offset_minute_signed(mut self, value: i8) -> Option<Self> {
451
0
        self.offset_minute = Some(value);
452
0
        Some(self)
453
0
    }
454
455
    /// Set the named component and return `self`.
456
    #[deprecated(
457
        since = "0.3.8",
458
        note = "use `parsed.with_offset_second_signed()` instead"
459
    )]
460
0
    pub const fn with_offset_second(self, value: u8) -> Option<Self> {
461
0
        if value > i8::MAX as u8 {
462
0
            None
463
        } else {
464
0
            self.with_offset_second_signed(value as _)
465
        }
466
0
    }
467
468
    /// Set the `offset_second` component and return `self`.
469
0
    pub const fn with_offset_second_signed(mut self, value: i8) -> Option<Self> {
470
0
        self.offset_second = Some(value);
471
0
        Some(self)
472
0
    }
473
}
474
475
impl TryFrom<Parsed> for Date {
476
    type Error = error::TryFromParsed;
477
478
0
    fn try_from(parsed: Parsed) -> Result<Self, Self::Error> {
479
        /// Match on the components that need to be present.
480
        macro_rules! match_ {
481
            (_ => $catch_all:expr $(,)?) => {
482
                $catch_all
483
            };
484
            (($($name:ident),* $(,)?) => $arm:expr, $($rest:tt)*) => {
485
                if let ($(Some($name)),*) = ($(parsed.$name()),*) {
486
                    $arm
487
                } else {
488
                    match_!($($rest)*)
489
                }
490
            };
491
        }
492
493
        /// Get the value needed to adjust the ordinal day for Sunday and Monday-based week
494
        /// numbering.
495
0
        const fn adjustment(year: i32) -> i16 {
496
0
            match Date::__from_ordinal_date_unchecked(year, 1).weekday() {
497
0
                Weekday::Monday => 7,
498
0
                Weekday::Tuesday => 1,
499
0
                Weekday::Wednesday => 2,
500
0
                Weekday::Thursday => 3,
501
0
                Weekday::Friday => 4,
502
0
                Weekday::Saturday => 5,
503
0
                Weekday::Sunday => 6,
504
            }
505
0
        }
506
507
        // TODO Only the basics have been covered. There are many other valid values that are not
508
        // currently constructed from the information known.
509
510
0
        match_! {
511
0
            (year, ordinal) => Ok(Self::from_ordinal_date(year, ordinal.get())?),
512
0
            (year, month, day) => Ok(Self::from_calendar_date(year, month, day.get())?),
513
0
            (iso_year, iso_week_number, weekday) => Ok(Self::from_iso_week_date(
514
0
                iso_year,
515
0
                iso_week_number.get(),
516
0
                weekday,
517
0
            )?),
518
0
            (year, sunday_week_number, weekday) => Ok(Self::from_ordinal_date(
519
0
                year,
520
0
                (sunday_week_number as i16 * 7 + weekday.number_days_from_sunday() as i16
521
0
                    - adjustment(year)
522
0
                    + 1) as u16,
523
0
            )?),
524
0
            (year, monday_week_number, weekday) => Ok(Self::from_ordinal_date(
525
0
                year,
526
0
                (monday_week_number as i16 * 7 + weekday.number_days_from_monday() as i16
527
0
                    - adjustment(year)
528
0
                    + 1) as u16,
529
0
            )?),
530
0
            _ => Err(InsufficientInformation),
531
        }
532
0
    }
533
}
534
535
impl TryFrom<Parsed> for Time {
536
    type Error = error::TryFromParsed;
537
538
0
    fn try_from(parsed: Parsed) -> Result<Self, Self::Error> {
539
0
        let hour = match (parsed.hour_24(), parsed.hour_12(), parsed.hour_12_is_pm()) {
540
0
            (Some(hour), _, _) => hour,
541
0
            (_, Some(hour), Some(false)) if hour.get() == 12 => 0,
542
0
            (_, Some(hour), Some(true)) if hour.get() == 12 => 12,
543
0
            (_, Some(hour), Some(false)) => hour.get(),
544
0
            (_, Some(hour), Some(true)) => hour.get() + 12,
545
0
            _ => return Err(InsufficientInformation),
546
        };
547
0
        if parsed.hour_24().is_none()
548
0
            && parsed.hour_12().is_some()
549
0
            && parsed.hour_12_is_pm().is_some()
550
0
            && parsed.minute().is_none()
551
0
            && parsed.second().is_none()
552
0
            && parsed.subsecond().is_none()
553
        {
554
0
            return Ok(Self::from_hms_nano(hour, 0, 0, 0)?);
555
0
        }
556
0
        let minute = parsed.minute().ok_or(InsufficientInformation)?;
557
0
        let second = parsed.second().unwrap_or(0);
558
0
        let subsecond = parsed.subsecond().unwrap_or(0);
559
0
        Ok(Self::from_hms_nano(hour, minute, second, subsecond)?)
560
0
    }
561
}
562
563
impl TryFrom<Parsed> for UtcOffset {
564
    type Error = error::TryFromParsed;
565
566
0
    fn try_from(parsed: Parsed) -> Result<Self, Self::Error> {
567
0
        let hour = parsed.offset_hour().ok_or(InsufficientInformation)?;
568
0
        let minute = parsed.offset_minute_signed().unwrap_or(0);
569
0
        let second = parsed.offset_second_signed().unwrap_or(0);
570
571
0
        Self::from_hms(hour, minute, second).map_err(|mut err| {
572
            // Provide the user a more accurate error.
573
0
            if err.name == "hours" {
574
0
                err.name = "offset hour";
575
0
            } else if err.name == "minutes" {
576
0
                err.name = "offset minute";
577
0
            } else if err.name == "seconds" {
578
0
                err.name = "offset second";
579
0
            }
580
0
            err.into()
581
0
        })
582
0
    }
583
}
584
585
impl TryFrom<Parsed> for PrimitiveDateTime {
586
    type Error = error::TryFromParsed;
587
588
0
    fn try_from(parsed: Parsed) -> Result<Self, Self::Error> {
589
0
        Ok(Self::new(parsed.try_into()?, parsed.try_into()?))
590
0
    }
591
}
592
593
impl TryFrom<Parsed> for OffsetDateTime {
594
    type Error = error::TryFromParsed;
595
596
    #[allow(clippy::unwrap_in_result)] // We know the values are valid.
597
0
    fn try_from(mut parsed: Parsed) -> Result<Self, Self::Error> {
598
        // Some well-known formats explicitly allow leap seconds. We don't currently support them,
599
        // so treat it as the nearest preceding moment that can be represented. Because leap seconds
600
        // always fall at the end of a month UTC, reject any that are at other times.
601
0
        let leap_second_input = if parsed.leap_second_allowed() && parsed.second() == Some(60) {
602
0
            parsed.set_second(59).expect("59 is a valid second");
603
0
            parsed
604
0
                .set_subsecond(999_999_999)
605
0
                .expect("999_999_999 is a valid subsecond");
606
0
            true
607
        } else {
608
0
            false
609
        };
610
0
        let dt = PrimitiveDateTime::try_from(parsed)?.assume_offset(parsed.try_into()?);
611
0
        if leap_second_input && !dt.is_valid_leap_second_stand_in() {
612
0
            return Err(error::TryFromParsed::ComponentRange(
613
0
                error::ComponentRange {
614
0
                    name: "second",
615
0
                    minimum: 0,
616
0
                    maximum: 59,
617
0
                    value: 60,
618
0
                    conditional_range: true,
619
0
                },
620
0
            ));
621
0
        }
622
0
        Ok(dt)
623
0
    }
624
}