1use 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;
13use crate::format_description::__private::{Component as ComponentV3, FormatDescriptionV3Inner};
14#[cfg(feature = "alloc")]
15use crate::format_description::OwnedFormatItem;
16use crate::format_description::{BorrowedFormatItem, Component, Period};
17use crate::internal_macros::{bug, const_try_opt};
18use crate::parsing::ParsedItem;
19use crate::parsing::component::{
20 parse_calendar_year_century_extended_range, parse_calendar_year_century_standard_range,
21 parse_calendar_year_full_extended_range, parse_calendar_year_full_standard_range,
22 parse_calendar_year_last_two, parse_day, parse_end, parse_hour_12, parse_hour_24, parse_ignore,
23 parse_iso_year_century_extended_range, parse_iso_year_century_standard_range,
24 parse_iso_year_full_extended_range, parse_iso_year_full_standard_range,
25 parse_iso_year_last_two, parse_minute, parse_month_long, parse_month_numerical,
26 parse_month_short, parse_offset_hour, parse_offset_minute, parse_offset_second, parse_ordinal,
27 parse_period, parse_second, parse_subsecond, parse_unix_timestamp_microsecond,
28 parse_unix_timestamp_millisecond, parse_unix_timestamp_nanosecond, parse_unix_timestamp_second,
29 parse_week_number_iso, parse_week_number_monday, parse_week_number_sunday, parse_weekday_long,
30 parse_weekday_monday, parse_weekday_short, parse_weekday_sunday,
31};
32use crate::unit::{Day, Hour, Minute, Nanosecond, Second};
33use crate::{
34 Date, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcDateTime, UtcOffset, Weekday, error,
35};
36
37mod sealed {
39 use super::*;
40
41 pub trait AnyFormatItem {
43 fn parse_item<'a>(
45 &self,
46 parsed: &mut Parsed,
47 input: &'a [u8],
48 ) -> Result<&'a [u8], error::ParseFromDescription>;
49 }
50}
51
52impl sealed::AnyFormatItem for BorrowedFormatItem<'_> {
53 #[inline(always)]
54 fn parse_item<'a>(
55 &self,
56 parsed: &mut Parsed,
57 input: &'a [u8],
58 ) -> Result<&'a [u8], error::ParseFromDescription> {
59 match self {
60 #[expect(deprecated)]
61 Self::Literal(literal) => Parsed::parse_literal(input, literal),
62 Self::StringLiteral(literal) => Parsed::parse_literal(input, literal.as_bytes()),
63 Self::Component(component) => parsed.parse_component(input, *component),
64 Self::Compound(compound) => parsed.parse_items(input, compound),
65 Self::Optional(item) => parsed.parse_item(input, *item).or(Ok(input)),
66 Self::First(items) => {
67 let mut first_err = None;
68
69 for item in items.iter() {
70 match parsed.parse_item(input, item) {
71 Ok(remaining_input) => return Ok(remaining_input),
72 Err(err) if first_err.is_none() => first_err = Some(err),
73 Err(_) => {}
74 }
75 }
76
77 match first_err {
78 Some(err) => Err(err),
79 None => Ok(input),
82 }
83 }
84 }
85 }
86}
87
88#[cfg(feature = "alloc")]
89impl sealed::AnyFormatItem for OwnedFormatItem {
90 #[inline]
91 fn parse_item<'a>(
92 &self,
93 parsed: &mut Parsed,
94 input: &'a [u8],
95 ) -> Result<&'a [u8], error::ParseFromDescription> {
96 match self {
97 #[expect(deprecated)]
98 Self::Literal(literal) => Parsed::parse_literal(input, literal),
99 Self::StringLiteral(literal) => Parsed::parse_literal(input, literal.as_bytes()),
100 Self::Component(component) => parsed.parse_component(input, *component),
101 Self::Compound(compound) => parsed.parse_items(input, compound),
102 Self::Optional(item) => parsed.parse_item(input, item.as_ref()).or(Ok(input)),
103 Self::First(items) => {
104 let mut first_err = None;
105
106 for item in items.iter() {
107 match parsed.parse_item(input, item) {
108 Ok(remaining_input) => return Ok(remaining_input),
109 Err(err) if first_err.is_none() => first_err = Some(err),
110 Err(_) => {}
111 }
112 }
113
114 match first_err {
115 Some(err) => Err(err),
116 None => Ok(input),
119 }
120 }
121 }
122 }
123}
124
125#[derive(Debug, Clone, Copy)]
132pub struct Parsed {
133 year: Option_ri32<{ MIN_YEAR }, { MAX_YEAR }>,
135 year_century: Option_ri16<{ (MIN_YEAR / 100) as i16 }, { (MAX_YEAR / 100) as i16 }>,
137 year_last_two: Option_ru8<0, 99>,
139 iso_year: Option_ri32<{ MIN_YEAR }, { MAX_YEAR }>,
141 iso_year_century: Option_ri16<{ (MIN_YEAR / 100) as i16 }, { (MAX_YEAR / 100) as i16 }>,
143 iso_year_last_two: Option_ru8<0, 99>,
145 month: Option<Month>,
147 sunday_week_number: Option_ru8<0, 53>,
149 monday_week_number: Option_ru8<0, 53>,
151 iso_week_number: Option_ru8<1, 53>,
153 weekday: Option<Weekday>,
155 ordinal: Option_ru16<1, 366>,
157 day: Option_ru8<1, 31>,
159 hour_24: Option_ru8<0, { Hour::per_t::<u8>(Day) - 1 }>,
161 hour_12: Option_ru8<1, 12>,
164 hour_12_is_pm: Option<bool>,
166 minute: Option_ru8<0, { Minute::per_t::<u8>(Hour) - 1 }>,
168 second: Option_ru8<0, { Second::per_t::<u8>(Minute) }>,
171 subsecond: Option_ru32<0, { Nanosecond::per_t::<u32>(Second) - 1 }>,
173 offset_hour: Option_ri8<-25, 25>,
175 offset_minute:
177 Option_ri8<{ -Minute::per_t::<i8>(Hour) + 1 }, { Minute::per_t::<i8>(Hour) - 1 }>,
178 offset_second:
180 Option_ri8<{ -Second::per_t::<i8>(Minute) + 1 }, { Second::per_t::<i8>(Minute) - 1 }>,
181 unix_timestamp_nanos: Option_ri128<
183 {
184 OffsetDateTime::new_in_offset(Date::MIN, Time::MIDNIGHT, UtcOffset::UTC)
185 .unix_timestamp_nanos()
186 },
187 {
188 OffsetDateTime::new_in_offset(Date::MAX, Time::MAX, UtcOffset::UTC)
189 .unix_timestamp_nanos()
190 },
191 >,
192 offset_is_negative: bool,
195 year_century_is_negative: bool,
198 iso_year_century_is_negative: bool,
201 pub(super) leap_second_allowed: bool,
204}
205
206impl Default for Parsed {
207 #[inline]
208 fn default() -> Self {
209 Self::new()
210 }
211}
212
213impl Parsed {
214 #[inline]
216 pub const fn new() -> Self {
217 Self {
218 year: Option_ri32::None,
219 year_century: Option_ri16::None,
220 year_last_two: Option_ru8::None,
221 iso_year: Option_ri32::None,
222 iso_year_century: Option_ri16::None,
223 iso_year_last_two: Option_ru8::None,
224 month: None,
225 sunday_week_number: Option_ru8::None,
226 monday_week_number: Option_ru8::None,
227 iso_week_number: Option_ru8::None,
228 weekday: None,
229 ordinal: Option_ru16::None,
230 day: Option_ru8::None,
231 hour_24: Option_ru8::None,
232 hour_12: Option_ru8::None,
233 hour_12_is_pm: None,
234 minute: Option_ru8::None,
235 second: Option_ru8::None,
236 subsecond: Option_ru32::None,
237 offset_hour: Option_ri8::None,
238 offset_minute: Option_ri8::None,
239 offset_second: Option_ri8::None,
240 unix_timestamp_nanos: Option_ri128::None,
241 offset_is_negative: false,
242 year_century_is_negative: false,
243 iso_year_century_is_negative: false,
244 leap_second_allowed: false,
245 }
246 }
247
248 #[inline]
251 pub(crate) fn parse_v3_inner<'a>(
252 &mut self,
253 mut input: &'a [u8],
254 format_description: &FormatDescriptionV3Inner<'_>,
255 ) -> Result<&'a [u8], error::ParseFromDescription> {
256 match format_description {
257 FormatDescriptionV3Inner::Component(component) => {
258 self.parse_component_v3(input, *component)
259 }
260 FormatDescriptionV3Inner::BorrowedLiteral(literal) => {
261 Self::parse_literal(input, literal.as_bytes())
262 }
263 FormatDescriptionV3Inner::BorrowedCompound(items) => {
264 let mut this = *self;
265 for item in *items {
266 input = this.parse_v3_inner(input, item)?;
267 }
268 *self = this;
269 Ok(input)
270 }
271 FormatDescriptionV3Inner::BorrowedOptional { format: _, item } => {
272 self.parse_v3_inner(input, item).or(Ok(input))
273 }
274 FormatDescriptionV3Inner::BorrowedFirst(items) => {
275 let mut first_err = None;
276
277 for item in items.iter() {
278 match self.parse_v3_inner(input, item) {
279 Ok(remaining_input) => return Ok(remaining_input),
280 Err(err) if first_err.is_none() => first_err = Some(err),
281 Err(_) => {}
282 }
283 }
284
285 match first_err {
286 Some(err) => Err(err),
287 None => Ok(input),
290 }
291 }
292 #[cfg(feature = "alloc")]
293 FormatDescriptionV3Inner::OwnedLiteral(literal) => {
294 Self::parse_literal(input, literal.as_bytes())
295 }
296 #[cfg(feature = "alloc")]
297 FormatDescriptionV3Inner::OwnedCompound(items) => {
298 let mut this = *self;
299 for item in items {
300 input = this.parse_v3_inner(input, item)?;
301 }
302 *self = this;
303 Ok(input)
304 }
305 #[cfg(feature = "alloc")]
306 FormatDescriptionV3Inner::OwnedOptional { format: _, item } => {
307 self.parse_v3_inner(input, item).or(Ok(input))
308 }
309 #[cfg(feature = "alloc")]
310 FormatDescriptionV3Inner::OwnedFirst(items) => {
311 let mut first_err = None;
312
313 for item in items {
314 match self.parse_v3_inner(input, item) {
315 Ok(remaining_input) => return Ok(remaining_input),
316 Err(err) if first_err.is_none() => first_err = Some(err),
317 Err(_) => {}
318 }
319 }
320
321 match first_err {
322 Some(err) => Err(err),
323 None => Ok(input),
326 }
327 }
328 }
329 }
330
331 #[inline]
334 fn parse_component_v3<'a>(
335 &mut self,
336 input: &'a [u8],
337 component: ComponentV3,
338 ) -> Result<&'a [u8], error::ParseFromDescription> {
339 use error::ParseFromDescription::InvalidComponent;
340
341 match component {
342 ComponentV3::Day(modifiers) => parse_day(input, modifiers)
343 .and_then(|parsed| parsed.consume_value(|value| self.set_day(value)))
344 .ok_or(InvalidComponent("day")),
345 ComponentV3::MonthShort(modifiers) => parse_month_short(input, modifiers)
346 .and_then(|parsed| parsed.consume_value(|value| self.set_month(value)))
347 .ok_or(InvalidComponent("month")),
348 ComponentV3::MonthLong(modifiers) => parse_month_long(input, modifiers)
349 .and_then(|parsed| parsed.consume_value(|value| self.set_month(value)))
350 .ok_or(InvalidComponent("month")),
351 ComponentV3::MonthNumerical(modifiers) => parse_month_numerical(input, modifiers)
352 .and_then(|parsed| parsed.consume_value(|value| self.set_month(value)))
353 .ok_or(InvalidComponent("month")),
354 ComponentV3::Ordinal(modifiers) => parse_ordinal(input, modifiers)
355 .and_then(|parsed| parsed.consume_value(|value| self.set_ordinal(value)))
356 .ok_or(InvalidComponent("ordinal")),
357 ComponentV3::WeekdayShort(modifiers) => parse_weekday_short(input, modifiers)
358 .and_then(|parsed| parsed.consume_value(|value| self.set_weekday(value)))
359 .ok_or(InvalidComponent("weekday")),
360 ComponentV3::WeekdayLong(modifiers) => parse_weekday_long(input, modifiers)
361 .and_then(|parsed| parsed.consume_value(|value| self.set_weekday(value)))
362 .ok_or(InvalidComponent("weekday")),
363 ComponentV3::WeekdaySunday(modifiers) => parse_weekday_sunday(input, modifiers)
364 .and_then(|parsed| parsed.consume_value(|value| self.set_weekday(value)))
365 .ok_or(InvalidComponent("weekday")),
366 ComponentV3::WeekdayMonday(modifiers) => parse_weekday_monday(input, modifiers)
367 .and_then(|parsed| parsed.consume_value(|value| self.set_weekday(value)))
368 .ok_or(InvalidComponent("weekday")),
369 ComponentV3::WeekNumberIso(modifiers) => parse_week_number_iso(input, modifiers)
370 .and_then(|parsed| {
371 parsed.consume_value(|value| self.set_iso_week_number(NonZero::new(value)?))
372 })
373 .ok_or(InvalidComponent("week number")),
374 ComponentV3::WeekNumberSunday(modifiers) => parse_week_number_sunday(input, modifiers)
375 .and_then(|parsed| parsed.consume_value(|value| self.set_sunday_week_number(value)))
376 .ok_or(InvalidComponent("week number")),
377 ComponentV3::WeekNumberMonday(modifiers) => parse_week_number_monday(input, modifiers)
378 .and_then(|parsed| parsed.consume_value(|value| self.set_monday_week_number(value)))
379 .ok_or(InvalidComponent("week number")),
380 ComponentV3::CalendarYearFullExtendedRange(modifiers) => {
381 parse_calendar_year_full_extended_range(input, modifiers)
382 .and_then(|parsed| parsed.consume_value(|value| self.set_year(value)))
383 .ok_or(InvalidComponent("year"))
384 }
385 ComponentV3::CalendarYearFullStandardRange(modifiers) => {
386 parse_calendar_year_full_standard_range(input, modifiers)
387 .and_then(|parsed| parsed.consume_value(|value| self.set_year(value)))
388 .ok_or(InvalidComponent("year"))
389 }
390 ComponentV3::IsoYearFullExtendedRange(modifiers) => {
391 parse_iso_year_full_extended_range(input, modifiers)
392 .and_then(|parsed| parsed.consume_value(|value| self.set_iso_year(value)))
393 .ok_or(InvalidComponent("year"))
394 }
395 ComponentV3::IsoYearFullStandardRange(modifiers) => {
396 parse_iso_year_full_standard_range(input, modifiers)
397 .and_then(|parsed| parsed.consume_value(|value| self.set_iso_year(value)))
398 .ok_or(InvalidComponent("year"))
399 }
400 ComponentV3::CalendarYearCenturyExtendedRange(modifiers) => {
401 parse_calendar_year_century_extended_range(input, modifiers)
402 .and_then(|parsed| {
403 parsed.consume_value(|(value, is_negative)| {
404 self.set_year_century(value, is_negative)
405 })
406 })
407 .ok_or(InvalidComponent("year"))
408 }
409 ComponentV3::CalendarYearCenturyStandardRange(modifiers) => {
410 parse_calendar_year_century_standard_range(input, modifiers)
411 .and_then(|parsed| {
412 parsed.consume_value(|(value, is_negative)| {
413 self.set_year_century(value, is_negative)
414 })
415 })
416 .ok_or(InvalidComponent("year"))
417 }
418 ComponentV3::IsoYearCenturyExtendedRange(modifiers) => {
419 parse_iso_year_century_extended_range(input, modifiers)
420 .and_then(|parsed| {
421 parsed.consume_value(|(value, is_negative)| {
422 self.set_iso_year_century(value, is_negative)
423 })
424 })
425 .ok_or(InvalidComponent("year"))
426 }
427 ComponentV3::IsoYearCenturyStandardRange(modifiers) => {
428 parse_iso_year_century_standard_range(input, modifiers)
429 .and_then(|parsed| {
430 parsed.consume_value(|(value, is_negative)| {
431 self.set_iso_year_century(value, is_negative)
432 })
433 })
434 .ok_or(InvalidComponent("year"))
435 }
436 ComponentV3::CalendarYearLastTwo(modifiers) => {
437 parse_calendar_year_last_two(input, modifiers)
438 .and_then(|parsed| parsed.consume_value(|value| self.set_year_last_two(value)))
439 .ok_or(InvalidComponent("year"))
440 }
441 ComponentV3::IsoYearLastTwo(modifiers) => parse_iso_year_last_two(input, modifiers)
442 .and_then(|parsed| parsed.consume_value(|value| self.set_iso_year_last_two(value)))
443 .ok_or(InvalidComponent("year")),
444 ComponentV3::Hour12(modifiers) => parse_hour_12(input, modifiers)
445 .and_then(|parsed| {
446 parsed.consume_value(|value| self.set_hour_12(NonZero::new(value)?))
447 })
448 .ok_or(InvalidComponent("hour")),
449 ComponentV3::Hour24(modifiers) => parse_hour_24(input, modifiers)
450 .and_then(|parsed| parsed.consume_value(|value| self.set_hour_24(value)))
451 .ok_or(InvalidComponent("hour")),
452 ComponentV3::Minute(modifiers) => parse_minute(input, modifiers)
453 .and_then(|parsed| parsed.consume_value(|value| self.set_minute(value)))
454 .ok_or(InvalidComponent("minute")),
455 ComponentV3::Period(modifiers) => parse_period(input, modifiers)
456 .and_then(|parsed| {
457 parsed.consume_value(|value| self.set_hour_12_is_pm(value == Period::Pm))
458 })
459 .ok_or(InvalidComponent("period")),
460 ComponentV3::Second(modifiers) => parse_second(input, modifiers)
461 .and_then(|parsed| parsed.consume_value(|value| self.set_second(value)))
462 .ok_or(InvalidComponent("second")),
463 ComponentV3::Subsecond(modifiers) => parse_subsecond(input, modifiers)
464 .and_then(|parsed| parsed.consume_value(|value| self.set_subsecond(value)))
465 .ok_or(InvalidComponent("subsecond")),
466 ComponentV3::OffsetHour(modifiers) => parse_offset_hour(input, modifiers)
467 .and_then(|parsed| {
468 parsed.consume_value(|(value, is_negative)| {
469 self.set_offset_hour(value)?;
470 self.offset_is_negative = is_negative;
471 Some(())
472 })
473 })
474 .ok_or(InvalidComponent("offset hour")),
475 ComponentV3::OffsetMinute(modifiers) => parse_offset_minute(input, modifiers)
476 .and_then(|parsed| {
477 parsed.consume_value(|value| self.set_offset_minute_signed(value))
478 })
479 .ok_or(InvalidComponent("offset minute")),
480 ComponentV3::OffsetSecond(modifiers) => parse_offset_second(input, modifiers)
481 .and_then(|parsed| {
482 parsed.consume_value(|value| self.set_offset_second_signed(value))
483 })
484 .ok_or(InvalidComponent("offset second")),
485 ComponentV3::Ignore(modifiers) => parse_ignore(input, modifiers)
486 .map(ParsedItem::<()>::into_inner)
487 .ok_or(InvalidComponent("ignore")),
488 ComponentV3::UnixTimestampSecond(modifiers) => {
489 parse_unix_timestamp_second(input, modifiers)
490 .and_then(|parsed| {
491 parsed.consume_value(|value| self.set_unix_timestamp_nanos(value))
492 })
493 .ok_or(InvalidComponent("unix_timestamp"))
494 }
495 ComponentV3::UnixTimestampMillisecond(modifiers) => {
496 parse_unix_timestamp_millisecond(input, modifiers)
497 .and_then(|parsed| {
498 parsed.consume_value(|value| self.set_unix_timestamp_nanos(value))
499 })
500 .ok_or(InvalidComponent("unix_timestamp"))
501 }
502 ComponentV3::UnixTimestampMicrosecond(modifiers) => {
503 parse_unix_timestamp_microsecond(input, modifiers)
504 .and_then(|parsed| {
505 parsed.consume_value(|value| self.set_unix_timestamp_nanos(value))
506 })
507 .ok_or(InvalidComponent("unix_timestamp"))
508 }
509 ComponentV3::UnixTimestampNanosecond(modifiers) => {
510 parse_unix_timestamp_nanosecond(input, modifiers)
511 .and_then(|parsed| {
512 parsed.consume_value(|value| self.set_unix_timestamp_nanos(value))
513 })
514 .ok_or(InvalidComponent("unix_timestamp"))
515 }
516 ComponentV3::End(modifiers) => parse_end(input, modifiers)
517 .map(ParsedItem::<()>::into_inner)
518 .ok_or(error::ParseFromDescription::UnexpectedTrailingCharacters),
519 }
520 }
521
522 #[inline]
528 pub fn parse_item<'a>(
529 &mut self,
530 input: &'a [u8],
531 item: &impl sealed::AnyFormatItem,
532 ) -> Result<&'a [u8], error::ParseFromDescription> {
533 item.parse_item(self, input)
534 }
535
536 #[inline]
542 pub fn parse_items<'a>(
543 &mut self,
544 mut input: &'a [u8],
545 items: &[impl sealed::AnyFormatItem],
546 ) -> Result<&'a [u8], error::ParseFromDescription> {
547 let mut this = *self;
550 for item in items {
551 input = this.parse_item(input, item)?;
552 }
553 *self = this;
554 Ok(input)
555 }
556
557 #[inline]
559 pub fn parse_literal<'a>(
560 input: &'a [u8],
561 literal: &[u8],
562 ) -> Result<&'a [u8], error::ParseFromDescription> {
563 input
564 .strip_prefix(literal)
565 .ok_or(error::ParseFromDescription::InvalidLiteral)
566 }
567
568 #[inline]
571 pub fn parse_component<'a>(
572 &mut self,
573 input: &'a [u8],
574 component: Component,
575 ) -> Result<&'a [u8], error::ParseFromDescription> {
576 self.parse_component_v3(input, component.into())
577 }
578}
579
580impl Parsed {
582 #[inline]
584 pub const fn year(&self) -> Option<i32> {
585 self.year.get_primitive()
586 }
587
588 #[inline]
593 pub const fn year_century(&self) -> Option<i16> {
594 self.year_century.get_primitive()
595 }
596
597 #[inline]
602 pub const fn year_century_is_negative(&self) -> Option<bool> {
603 match self.year_century() {
604 Some(_) => Some(self.year_century_is_negative),
605 None => None,
606 }
607 }
608
609 #[inline]
611 pub const fn year_last_two(&self) -> Option<u8> {
612 self.year_last_two.get_primitive()
613 }
614
615 #[inline]
617 pub const fn iso_year(&self) -> Option<i32> {
618 self.iso_year.get_primitive()
619 }
620
621 #[inline]
626 pub const fn iso_year_century(&self) -> Option<i16> {
627 self.iso_year_century.get_primitive()
628 }
629
630 #[inline]
635 pub const fn iso_year_century_is_negative(&self) -> Option<bool> {
636 match self.iso_year_century() {
637 Some(_) => Some(self.iso_year_century_is_negative),
638 None => None,
639 }
640 }
641
642 #[inline]
644 pub const fn iso_year_last_two(&self) -> Option<u8> {
645 self.iso_year_last_two.get_primitive()
646 }
647
648 #[inline]
650 pub const fn month(&self) -> Option<Month> {
651 self.month
652 }
653
654 #[inline]
656 pub const fn sunday_week_number(&self) -> Option<u8> {
657 self.sunday_week_number.get_primitive()
658 }
659
660 #[inline]
662 pub const fn monday_week_number(&self) -> Option<u8> {
663 self.monday_week_number.get_primitive()
664 }
665
666 #[inline]
668 pub const fn iso_week_number(&self) -> Option<NonZero<u8>> {
669 NonZero::new(const_try_opt!(self.iso_week_number.get_primitive()))
670 }
671
672 #[inline]
674 pub const fn weekday(&self) -> Option<Weekday> {
675 self.weekday
676 }
677
678 #[inline]
680 pub const fn ordinal(&self) -> Option<NonZero<u16>> {
681 NonZero::new(const_try_opt!(self.ordinal.get_primitive()))
682 }
683
684 #[inline]
686 pub const fn day(&self) -> Option<NonZero<u8>> {
687 NonZero::new(const_try_opt!(self.day.get_primitive()))
688 }
689
690 #[inline]
692 pub const fn hour_24(&self) -> Option<u8> {
693 self.hour_24.get_primitive()
694 }
695
696 #[inline]
698 pub const fn hour_12(&self) -> Option<NonZero<u8>> {
699 NonZero::new(const_try_opt!(self.hour_12.get_primitive()))
700 }
701
702 #[inline]
704 pub const fn hour_12_is_pm(&self) -> Option<bool> {
705 self.hour_12_is_pm
706 }
707
708 #[inline]
710 pub const fn minute(&self) -> Option<u8> {
711 self.minute.get_primitive()
712 }
713
714 #[inline]
716 pub const fn second(&self) -> Option<u8> {
717 self.second.get_primitive()
718 }
719
720 #[inline]
722 pub const fn subsecond(&self) -> Option<u32> {
723 self.subsecond.get_primitive()
724 }
725
726 #[inline]
728 pub const fn offset_hour(&self) -> Option<i8> {
729 self.offset_hour.get_primitive()
730 }
731
732 #[doc(hidden)]
734 #[deprecated(since = "0.3.8", note = "use `parsed.offset_minute_signed()` instead")]
735 #[inline]
736 pub const fn offset_minute(&self) -> Option<u8> {
737 Some(const_try_opt!(self.offset_minute_signed()).unsigned_abs())
738 }
739
740 #[inline]
742 pub const fn offset_minute_signed(&self) -> Option<i8> {
743 match (self.offset_minute.get_primitive(), self.offset_is_negative) {
744 (Some(offset_minute), true) => Some(-offset_minute),
745 (Some(offset_minute), _) => Some(offset_minute),
746 (None, _) => None,
747 }
748 }
749
750 #[doc(hidden)]
752 #[deprecated(since = "0.3.8", note = "use `parsed.offset_second_signed()` instead")]
753 #[inline]
754 pub const fn offset_second(&self) -> Option<u8> {
755 Some(const_try_opt!(self.offset_second_signed()).unsigned_abs())
756 }
757
758 #[inline]
760 pub const fn offset_second_signed(&self) -> Option<i8> {
761 match (self.offset_second.get_primitive(), self.offset_is_negative) {
762 (Some(offset_second), true) => Some(-offset_second),
763 (Some(offset_second), _) => Some(offset_second),
764 (None, _) => None,
765 }
766 }
767
768 #[inline]
770 pub const fn unix_timestamp_nanos(&self) -> Option<i128> {
771 self.unix_timestamp_nanos.get_primitive()
772 }
773}
774
775macro_rules! setters {
777 ($($name:ident $setter:ident $builder:ident $type:ty;)*) => {$(
778 #[doc = concat!("Set the `", stringify!($name), "` component.")]
779 #[inline]
780 pub const fn $setter(&mut self, value: $type) -> Option<()> {
781 match self.$builder(value) {
782 Some(value) => {
783 *self = value;
784 Some(())
785 },
786 None => None,
787 }
788 }
789 )*};
790}
791
792impl Parsed {
797 setters! {
798 year set_year with_year i32;
799 }
800
801 #[inline]
806 pub const fn set_year_century(&mut self, value: i16, is_negative: bool) -> Option<()> {
807 self.year_century = Option_ri16::Some(const_try_opt!(ri16::new(value)));
808 if value != 0 {
809 self.year_century_is_negative = value.is_negative();
810 } else {
811 self.year_century_is_negative = is_negative;
812 }
813 Some(())
814 }
815
816 setters! {
817 year_last_two set_year_last_two with_year_last_two u8;
818 iso_year set_iso_year with_iso_year i32;
819 iso_year_last_two set_iso_year_last_two with_iso_year_last_two u8;
820 }
821
822 #[inline]
827 pub const fn set_iso_year_century(&mut self, value: i16, is_negative: bool) -> Option<()> {
828 self.iso_year_century = Option_ri16::Some(const_try_opt!(ri16::new(value)));
829 if value != 0 {
830 self.iso_year_century_is_negative = value.is_negative();
831 } else {
832 self.iso_year_century_is_negative = is_negative;
833 }
834 Some(())
835 }
836
837 setters! {
838 month set_month with_month Month;
839 sunday_week_number set_sunday_week_number with_sunday_week_number u8;
840 monday_week_number set_monday_week_number with_monday_week_number u8;
841 iso_week_number set_iso_week_number with_iso_week_number NonZero<u8>;
842 weekday set_weekday with_weekday Weekday;
843 ordinal set_ordinal with_ordinal NonZero<u16>;
844 day set_day with_day NonZero<u8>;
845 hour_24 set_hour_24 with_hour_24 u8;
846 hour_12 set_hour_12 with_hour_12 NonZero<u8>;
847 hour_12_is_pm set_hour_12_is_pm with_hour_12_is_pm bool;
848 minute set_minute with_minute u8;
849 second set_second with_second u8;
850 subsecond set_subsecond with_subsecond u32;
851 offset_hour set_offset_hour with_offset_hour i8;
852 offset_minute set_offset_minute_signed with_offset_minute_signed i8;
853 offset_second set_offset_second_signed with_offset_second_signed i8;
854 unix_timestamp_nanos set_unix_timestamp_nanos with_unix_timestamp_nanos i128;
855 }
856
857 #[doc(hidden)]
859 #[deprecated(
860 since = "0.3.8",
861 note = "use `parsed.set_offset_minute_signed()` instead"
862 )]
863 #[inline]
864 pub const fn set_offset_minute(&mut self, value: u8) -> Option<()> {
865 if value > i8::MAX.cast_unsigned() {
866 None
867 } else {
868 self.set_offset_minute_signed(value.cast_signed())
869 }
870 }
871
872 #[doc(hidden)]
874 #[deprecated(
875 since = "0.3.8",
876 note = "use `parsed.set_offset_second_signed()` instead"
877 )]
878 #[inline]
879 pub const fn set_offset_second(&mut self, value: u8) -> Option<()> {
880 if value > i8::MAX.cast_unsigned() {
881 None
882 } else {
883 self.set_offset_second_signed(value.cast_signed())
884 }
885 }
886}
887
888impl Parsed {
893 #[inline]
895 pub const fn with_year(mut self, value: i32) -> Option<Self> {
896 self.year = Option_ri32::Some(const_try_opt!(ri32::new(value)));
897 Some(self)
898 }
899
900 #[inline]
905 pub const fn with_year_century(mut self, value: i16, is_negative: bool) -> Option<Self> {
906 self.year_century = Option_ri16::Some(const_try_opt!(ri16::new(value)));
907 if value != 0 {
908 self.year_century_is_negative = value.is_negative();
909 } else {
910 self.year_century_is_negative = is_negative;
911 }
912 Some(self)
913 }
914
915 #[inline]
917 pub const fn with_year_last_two(mut self, value: u8) -> Option<Self> {
918 self.year_last_two = Option_ru8::Some(const_try_opt!(ru8::new(value)));
919 Some(self)
920 }
921
922 #[inline]
924 pub const fn with_iso_year(mut self, value: i32) -> Option<Self> {
925 self.iso_year = Option_ri32::Some(const_try_opt!(ri32::new(value)));
926 Some(self)
927 }
928
929 #[inline]
934 pub const fn with_iso_year_century(mut self, value: i16, is_negative: bool) -> Option<Self> {
935 self.iso_year_century = Option_ri16::Some(const_try_opt!(ri16::new(value)));
936 if value != 0 {
937 self.iso_year_century_is_negative = value.is_negative();
938 } else {
939 self.iso_year_century_is_negative = is_negative;
940 }
941 Some(self)
942 }
943
944 #[inline]
946 pub const fn with_iso_year_last_two(mut self, value: u8) -> Option<Self> {
947 self.iso_year_last_two = Option_ru8::Some(const_try_opt!(ru8::new(value)));
948 Some(self)
949 }
950
951 #[inline]
953 pub const fn with_month(mut self, value: Month) -> Option<Self> {
954 self.month = Some(value);
955 Some(self)
956 }
957
958 #[inline]
960 pub const fn with_sunday_week_number(mut self, value: u8) -> Option<Self> {
961 self.sunday_week_number = Option_ru8::Some(const_try_opt!(ru8::new(value)));
962 Some(self)
963 }
964
965 #[inline]
967 pub const fn with_monday_week_number(mut self, value: u8) -> Option<Self> {
968 self.monday_week_number = Option_ru8::Some(const_try_opt!(ru8::new(value)));
969 Some(self)
970 }
971
972 #[inline]
974 pub const fn with_iso_week_number(mut self, value: NonZero<u8>) -> Option<Self> {
975 self.iso_week_number = Option_ru8::Some(const_try_opt!(ru8::new(value.get())));
976 Some(self)
977 }
978
979 #[inline]
981 pub const fn with_weekday(mut self, value: Weekday) -> Option<Self> {
982 self.weekday = Some(value);
983 Some(self)
984 }
985
986 #[inline]
988 pub const fn with_ordinal(mut self, value: NonZero<u16>) -> Option<Self> {
989 self.ordinal = Option_ru16::Some(const_try_opt!(ru16::new(value.get())));
990 Some(self)
991 }
992
993 #[inline]
995 pub const fn with_day(mut self, value: NonZero<u8>) -> Option<Self> {
996 self.day = Option_ru8::Some(const_try_opt!(ru8::new(value.get())));
997 Some(self)
998 }
999
1000 #[inline]
1002 pub const fn with_hour_24(mut self, value: u8) -> Option<Self> {
1003 self.hour_24 = Option_ru8::Some(const_try_opt!(ru8::new(value)));
1004 Some(self)
1005 }
1006
1007 #[inline]
1009 pub const fn with_hour_12(mut self, value: NonZero<u8>) -> Option<Self> {
1010 self.hour_12 = Option_ru8::Some(const_try_opt!(ru8::new(value.get())));
1011 Some(self)
1012 }
1013
1014 #[inline]
1016 pub const fn with_hour_12_is_pm(mut self, value: bool) -> Option<Self> {
1017 self.hour_12_is_pm = Some(value);
1018 Some(self)
1019 }
1020
1021 #[inline]
1023 pub const fn with_minute(mut self, value: u8) -> Option<Self> {
1024 self.minute = Option_ru8::Some(const_try_opt!(ru8::new(value)));
1025 Some(self)
1026 }
1027
1028 #[inline]
1030 pub const fn with_second(mut self, value: u8) -> Option<Self> {
1031 self.second = Option_ru8::Some(const_try_opt!(ru8::new(value)));
1032 Some(self)
1033 }
1034
1035 #[inline]
1037 pub const fn with_subsecond(mut self, value: u32) -> Option<Self> {
1038 self.subsecond = Option_ru32::Some(const_try_opt!(ru32::new(value)));
1039 Some(self)
1040 }
1041
1042 #[inline]
1044 pub const fn with_offset_hour(mut self, value: i8) -> Option<Self> {
1045 self.offset_hour = Option_ri8::Some(const_try_opt!(ri8::new(value)));
1046 Some(self)
1047 }
1048
1049 #[doc(hidden)]
1051 #[deprecated(
1052 since = "0.3.8",
1053 note = "use `parsed.with_offset_minute_signed()` instead"
1054 )]
1055 #[inline]
1056 pub const fn with_offset_minute(self, value: u8) -> Option<Self> {
1057 if value > i8::MAX.cast_unsigned() {
1058 None
1059 } else {
1060 self.with_offset_minute_signed(value.cast_signed())
1061 }
1062 }
1063
1064 #[inline]
1066 pub const fn with_offset_minute_signed(mut self, value: i8) -> Option<Self> {
1067 self.offset_minute = Option_ri8::Some(const_try_opt!(ri8::new(value)));
1068 Some(self)
1069 }
1070
1071 #[doc(hidden)]
1073 #[deprecated(
1074 since = "0.3.8",
1075 note = "use `parsed.with_offset_second_signed()` instead"
1076 )]
1077 #[inline]
1078 pub const fn with_offset_second(self, value: u8) -> Option<Self> {
1079 if value > i8::MAX.cast_unsigned() {
1080 None
1081 } else {
1082 self.with_offset_second_signed(value.cast_signed())
1083 }
1084 }
1085
1086 #[inline]
1088 pub const fn with_offset_second_signed(mut self, value: i8) -> Option<Self> {
1089 self.offset_second = Option_ri8::Some(const_try_opt!(ri8::new(value)));
1090 Some(self)
1091 }
1092
1093 #[inline]
1095 pub const fn with_unix_timestamp_nanos(mut self, value: i128) -> Option<Self> {
1096 self.unix_timestamp_nanos = Option_ri128::Some(const_try_opt!(ri128::new(value)));
1097 Some(self)
1098 }
1099}
1100
1101impl TryFrom<Parsed> for Date {
1102 type Error = error::TryFromParsed;
1103
1104 #[inline]
1105 fn try_from(mut parsed: Parsed) -> Result<Self, Self::Error> {
1106 macro_rules! match_ {
1108 (_ => $catch_all:expr $(,)?) => {
1109 $catch_all
1110 };
1111 (($($name:ident),* $(,)?) => $arm:expr, $($rest:tt)*) => {
1112 if let ($(Some($name)),*) = ($(parsed.$name()),*) {
1113 $arm
1114 } else {
1115 match_!($($rest)*)
1116 }
1117 };
1118 }
1119
1120 #[inline]
1123 const fn adjustment(year: i32) -> i16 {
1124 match unsafe { Date::__from_ordinal_date_unchecked(year, 1) }.weekday() {
1126 Weekday::Monday => 7,
1127 Weekday::Tuesday => 1,
1128 Weekday::Wednesday => 2,
1129 Weekday::Thursday => 3,
1130 Weekday::Friday => 4,
1131 Weekday::Saturday => 5,
1132 Weekday::Sunday => 6,
1133 }
1134 }
1135
1136 if let (None, Some(century), Some(is_negative), Some(last_two)) = (
1139 parsed.year(),
1140 parsed.year_century(),
1141 parsed.year_century_is_negative(),
1142 parsed.year_last_two(),
1143 ) {
1144 let year = if is_negative {
1145 100 * century.extend::<i32>() - last_two.cast_signed().extend::<i32>()
1146 } else {
1147 100 * century.extend::<i32>() + last_two.cast_signed().extend::<i32>()
1148 };
1149 parsed.year = Option_ri32::from(ri32::new(year));
1150 }
1151 if let (None, Some(century), Some(is_negative), Some(last_two)) = (
1152 parsed.iso_year(),
1153 parsed.iso_year_century(),
1154 parsed.iso_year_century_is_negative(),
1155 parsed.iso_year_last_two(),
1156 ) {
1157 let iso_year = if is_negative {
1158 100 * century.extend::<i32>() - last_two.cast_signed().extend::<i32>()
1159 } else {
1160 100 * century.extend::<i32>() + last_two.cast_signed().extend::<i32>()
1161 };
1162 parsed.iso_year = Option_ri32::from(ri32::new(iso_year));
1163 }
1164
1165 match_! {
1166 (year, ordinal) => Ok(Self::from_ordinal_date(year, ordinal.get())?),
1167 (year, month, day) => Ok(Self::from_calendar_date(year, month, day.get())?),
1168 (iso_year, iso_week_number, weekday) => Ok(Self::from_iso_week_date(
1169 iso_year,
1170 iso_week_number.get(),
1171 weekday,
1172 )?),
1173 (year, sunday_week_number, weekday) => Ok(Self::from_ordinal_date(
1174 year,
1175 (sunday_week_number.cast_signed().extend::<i16>() * 7
1176 + weekday.number_days_from_sunday().cast_signed().extend::<i16>()
1177 - adjustment(year)
1178 + 1).cast_unsigned(),
1179 )?),
1180 (year, monday_week_number, weekday) => Ok(Self::from_ordinal_date(
1181 year,
1182 (monday_week_number.cast_signed().extend::<i16>() * 7
1183 + weekday.number_days_from_monday().cast_signed().extend::<i16>()
1184 - adjustment(year)
1185 + 1).cast_unsigned(),
1186 )?),
1187 _ => Err(InsufficientInformation),
1188 }
1189 }
1190}
1191
1192impl TryFrom<Parsed> for Time {
1193 type Error = error::TryFromParsed;
1194
1195 #[inline]
1196 fn try_from(parsed: Parsed) -> Result<Self, Self::Error> {
1197 let hour = match (parsed.hour_24(), parsed.hour_12(), parsed.hour_12_is_pm()) {
1198 (Some(hour), _, _) => hour,
1199 (_, Some(hour), Some(false)) if hour.get() == 12 => 0,
1200 (_, Some(hour), Some(true)) if hour.get() == 12 => 12,
1201 (_, Some(hour), Some(false)) => hour.get(),
1202 (_, Some(hour), Some(true)) => hour.get() + 12,
1203 _ => return Err(InsufficientInformation),
1204 };
1205
1206 if parsed.hour_24().is_none()
1207 && parsed.hour_12().is_some()
1208 && parsed.hour_12_is_pm().is_some()
1209 && parsed.minute().is_none()
1210 && parsed.second().is_none()
1211 && parsed.subsecond().is_none()
1212 {
1213 return Ok(Self::from_hms_nano(hour, 0, 0, 0)?);
1214 }
1215
1216 match (parsed.minute(), parsed.second(), parsed.subsecond()) {
1218 (None, None, None) => Ok(Self::from_hms_nano(hour, 0, 0, 0)?),
1219 (Some(minute), None, None) => Ok(Self::from_hms_nano(hour, minute, 0, 0)?),
1220 (Some(minute), Some(second), None) => Ok(Self::from_hms_nano(hour, minute, second, 0)?),
1221 (Some(minute), Some(second), Some(subsecond)) => {
1222 Ok(Self::from_hms_nano(hour, minute, second, subsecond)?)
1223 }
1224 _ => Err(InsufficientInformation),
1225 }
1226 }
1227}
1228
1229#[inline]
1230fn utc_offset_try_from_parsed<const REQUIRED: bool>(
1231 parsed: Parsed,
1232) -> Result<UtcOffset, error::TryFromParsed> {
1233 let hour = match (REQUIRED, parsed.offset_hour()) {
1234 (true, None) => return Err(InsufficientInformation),
1236 (false, None) => return Ok(UtcOffset::UTC),
1239 (_, Some(hour)) => hour,
1241 };
1242 let minute = parsed.offset_minute_signed();
1243 let second = minute.and_then(|_| parsed.offset_second_signed());
1245
1246 let minute = minute.unwrap_or(0);
1247 let second = second.unwrap_or(0);
1248
1249 UtcOffset::from_hms(hour, minute, second).map_err(Into::into)
1250}
1251
1252impl TryFrom<Parsed> for UtcOffset {
1253 type Error = error::TryFromParsed;
1254
1255 #[inline]
1256 fn try_from(parsed: Parsed) -> Result<Self, Self::Error> {
1257 utc_offset_try_from_parsed::<true>(parsed)
1258 }
1259}
1260
1261impl TryFrom<Parsed> for PrimitiveDateTime {
1262 type Error = error::TryFromParsed;
1263
1264 #[inline]
1265 fn try_from(parsed: Parsed) -> Result<Self, Self::Error> {
1266 Ok(Self::new(parsed.try_into()?, parsed.try_into()?))
1267 }
1268}
1269
1270impl TryFrom<Parsed> for UtcDateTime {
1271 type Error = error::TryFromParsed;
1272
1273 #[inline]
1274 fn try_from(mut parsed: Parsed) -> Result<Self, Self::Error> {
1275 if let Some(timestamp) = parsed.unix_timestamp_nanos() {
1276 let mut value = Self::from_unix_timestamp_nanos(timestamp)?;
1277 if let Some(subsecond) = parsed.subsecond() {
1278 value = value.replace_nanosecond(subsecond)?;
1279 }
1280 return Ok(value);
1281 }
1282
1283 let leap_second_input = if parsed.leap_second_allowed && parsed.second() == Some(60) {
1287 if parsed.set_second(59).is_none() {
1288 bug!("59 is a valid second");
1289 }
1290 if parsed.set_subsecond(999_999_999).is_none() {
1291 bug!("999_999_999 is a valid subsecond");
1292 }
1293 true
1294 } else {
1295 false
1296 };
1297
1298 let dt = OffsetDateTime::new_in_offset(
1299 Date::try_from(parsed)?,
1300 Time::try_from(parsed)?,
1301 utc_offset_try_from_parsed::<false>(parsed)?,
1302 )
1303 .to_utc();
1304
1305 if leap_second_input && !dt.is_valid_leap_second_stand_in() {
1306 return Err(error::TryFromParsed::ComponentRange(
1307 error::ComponentRange::conditional("second"),
1308 ));
1309 }
1310 Ok(dt)
1311 }
1312}
1313
1314impl TryFrom<Parsed> for OffsetDateTime {
1315 type Error = error::TryFromParsed;
1316
1317 #[inline]
1318 fn try_from(mut parsed: Parsed) -> Result<Self, Self::Error> {
1319 if let Some(timestamp) = parsed.unix_timestamp_nanos() {
1320 let mut value = Self::from_unix_timestamp_nanos(timestamp)?;
1321 if let Some(subsecond) = parsed.subsecond() {
1322 value = value.replace_nanosecond(subsecond)?;
1323 }
1324 return Ok(value);
1325 }
1326
1327 let leap_second_input = if parsed.leap_second_allowed && parsed.second() == Some(60) {
1331 if parsed.set_second(59).is_none() {
1332 bug!("59 is a valid second");
1333 }
1334 if parsed.set_subsecond(999_999_999).is_none() {
1335 bug!("999_999_999 is a valid subsecond");
1336 }
1337 true
1338 } else {
1339 false
1340 };
1341
1342 let dt = Self::new_in_offset(
1343 Date::try_from(parsed)?,
1344 Time::try_from(parsed)?,
1345 UtcOffset::try_from(parsed)?,
1346 );
1347
1348 if leap_second_input && !dt.is_valid_leap_second_stand_in() {
1349 return Err(error::TryFromParsed::ComponentRange(
1350 error::ComponentRange::conditional("second"),
1351 ));
1352 }
1353 Ok(dt)
1354 }
1355}