1use core::num::NonZero;
4
5use deranged::{
6 OptionRangedI8, OptionRangedI16, OptionRangedI32, OptionRangedI128, OptionRangedU8,
7 OptionRangedU16, OptionRangedU32, RangedI8, RangedI16, RangedI32, RangedI128, RangedU8,
8 RangedU16, RangedU32,
9};
10use num_conv::prelude::*;
11
12use crate::convert::{Day, Hour, Minute, Nanosecond, Second};
13use crate::date::{MAX_YEAR, MIN_YEAR};
14use crate::error::TryFromParsed::InsufficientInformation;
15#[cfg(feature = "alloc")]
16use crate::format_description::OwnedFormatItem;
17use crate::format_description::{BorrowedFormatItem, Component, modifier};
18use crate::internal_macros::{bug, const_try_opt};
19use crate::parsing::ParsedItem;
20use crate::parsing::component::{
21 Period, parse_day, parse_end, parse_hour, parse_ignore, parse_minute, parse_month,
22 parse_offset_hour, parse_offset_minute, parse_offset_second, parse_ordinal, parse_period,
23 parse_second, parse_subsecond, parse_unix_timestamp, parse_week_number, parse_weekday,
24 parse_year,
25};
26use crate::{
27 Date, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcDateTime, UtcOffset, Weekday, error,
28};
29
30mod sealed {
32 use super::*;
33
34 pub trait AnyFormatItem {
36 fn parse_item<'a>(
38 &self,
39 parsed: &mut Parsed,
40 input: &'a [u8],
41 ) -> Result<&'a [u8], error::ParseFromDescription>;
42 }
43}
44
45impl sealed::AnyFormatItem for BorrowedFormatItem<'_> {
46 #[inline]
47 fn parse_item<'a>(
48 &self,
49 parsed: &mut Parsed,
50 input: &'a [u8],
51 ) -> Result<&'a [u8], error::ParseFromDescription> {
52 match self {
53 Self::Literal(literal) => Parsed::parse_literal(input, literal),
54 Self::Component(component) => parsed.parse_component(input, *component),
55 Self::Compound(compound) => parsed.parse_items(input, compound),
56 Self::Optional(item) => parsed.parse_item(input, *item).or(Ok(input)),
57 Self::First(items) => {
58 let mut first_err = None;
59
60 for item in items.iter() {
61 match parsed.parse_item(input, item) {
62 Ok(remaining_input) => return Ok(remaining_input),
63 Err(err) if first_err.is_none() => first_err = Some(err),
64 Err(_) => {}
65 }
66 }
67
68 match first_err {
69 Some(err) => Err(err),
70 None => Ok(input),
73 }
74 }
75 }
76 }
77}
78
79#[cfg(feature = "alloc")]
80impl sealed::AnyFormatItem for OwnedFormatItem {
81 #[inline]
82 fn parse_item<'a>(
83 &self,
84 parsed: &mut Parsed,
85 input: &'a [u8],
86 ) -> Result<&'a [u8], error::ParseFromDescription> {
87 match self {
88 Self::Literal(literal) => Parsed::parse_literal(input, literal),
89 Self::Component(component) => parsed.parse_component(input, *component),
90 Self::Compound(compound) => parsed.parse_items(input, compound),
91 Self::Optional(item) => parsed.parse_item(input, item.as_ref()).or(Ok(input)),
92 Self::First(items) => {
93 let mut first_err = None;
94
95 for item in items.iter() {
96 match parsed.parse_item(input, item) {
97 Ok(remaining_input) => return Ok(remaining_input),
98 Err(err) if first_err.is_none() => first_err = Some(err),
99 Err(_) => {}
100 }
101 }
102
103 match first_err {
104 Some(err) => Err(err),
105 None => Ok(input),
108 }
109 }
110 }
111 }
112}
113
114#[derive(Debug, Clone, Copy)]
121pub struct Parsed {
122 year: OptionRangedI32<{ MIN_YEAR }, { MAX_YEAR }>,
124 year_century: OptionRangedI16<{ (MIN_YEAR / 100) as i16 }, { (MAX_YEAR / 100) as i16 }>,
126 year_last_two: OptionRangedU8<0, 99>,
128 iso_year: OptionRangedI32<{ MIN_YEAR }, { MAX_YEAR }>,
130 iso_year_century: OptionRangedI16<{ (MIN_YEAR / 100) as i16 }, { (MAX_YEAR / 100) as i16 }>,
132 iso_year_last_two: OptionRangedU8<0, 99>,
134 month: Option<Month>,
136 sunday_week_number: OptionRangedU8<0, 53>,
138 monday_week_number: OptionRangedU8<0, 53>,
140 iso_week_number: OptionRangedU8<1, 53>,
142 weekday: Option<Weekday>,
144 ordinal: OptionRangedU16<1, 366>,
146 day: OptionRangedU8<1, 31>,
148 hour_24: OptionRangedU8<0, { Hour::per_t::<u8>(Day) - 1 }>,
150 hour_12: OptionRangedU8<1, 12>,
153 hour_12_is_pm: Option<bool>,
155 minute: OptionRangedU8<0, { Minute::per_t::<u8>(Hour) - 1 }>,
157 second: OptionRangedU8<0, { Second::per_t::<u8>(Minute) }>,
160 subsecond: OptionRangedU32<0, { Nanosecond::per_t::<u32>(Second) - 1 }>,
162 offset_hour: OptionRangedI8<-23, 23>,
164 offset_minute:
166 OptionRangedI8<{ -Minute::per_t::<i8>(Hour) + 1 }, { Minute::per_t::<i8>(Hour) - 1 }>,
167 offset_second:
169 OptionRangedI8<{ -Second::per_t::<i8>(Minute) + 1 }, { Second::per_t::<i8>(Minute) - 1 }>,
170 unix_timestamp_nanos: OptionRangedI128<
172 {
173 OffsetDateTime::new_in_offset(Date::MIN, Time::MIDNIGHT, UtcOffset::UTC)
174 .unix_timestamp_nanos()
175 },
176 {
177 OffsetDateTime::new_in_offset(Date::MAX, Time::MAX, UtcOffset::UTC)
178 .unix_timestamp_nanos()
179 },
180 >,
181 offset_is_negative: bool,
184 year_century_is_negative: bool,
187 iso_year_century_is_negative: bool,
190 pub(super) leap_second_allowed: bool,
193}
194
195impl Default for Parsed {
196 #[inline]
197 fn default() -> Self {
198 Self::new()
199 }
200}
201
202impl Parsed {
203 #[inline]
205 pub const fn new() -> Self {
206 Self {
207 year: OptionRangedI32::None,
208 year_century: OptionRangedI16::None,
209 year_last_two: OptionRangedU8::None,
210 iso_year: OptionRangedI32::None,
211 iso_year_century: OptionRangedI16::None,
212 iso_year_last_two: OptionRangedU8::None,
213 month: None,
214 sunday_week_number: OptionRangedU8::None,
215 monday_week_number: OptionRangedU8::None,
216 iso_week_number: OptionRangedU8::None,
217 weekday: None,
218 ordinal: OptionRangedU16::None,
219 day: OptionRangedU8::None,
220 hour_24: OptionRangedU8::None,
221 hour_12: OptionRangedU8::None,
222 hour_12_is_pm: None,
223 minute: OptionRangedU8::None,
224 second: OptionRangedU8::None,
225 subsecond: OptionRangedU32::None,
226 offset_hour: OptionRangedI8::None,
227 offset_minute: OptionRangedI8::None,
228 offset_second: OptionRangedI8::None,
229 unix_timestamp_nanos: OptionRangedI128::None,
230 offset_is_negative: false,
231 year_century_is_negative: false,
232 iso_year_century_is_negative: false,
233 leap_second_allowed: false,
234 }
235 }
236
237 #[inline]
243 pub fn parse_item<'a>(
244 &mut self,
245 input: &'a [u8],
246 item: &impl sealed::AnyFormatItem,
247 ) -> Result<&'a [u8], error::ParseFromDescription> {
248 item.parse_item(self, input)
249 }
250
251 #[inline]
257 pub fn parse_items<'a>(
258 &mut self,
259 mut input: &'a [u8],
260 items: &[impl sealed::AnyFormatItem],
261 ) -> Result<&'a [u8], error::ParseFromDescription> {
262 let mut this = *self;
265 for item in items {
266 input = this.parse_item(input, item)?;
267 }
268 *self = this;
269 Ok(input)
270 }
271
272 #[inline]
274 pub fn parse_literal<'a>(
275 input: &'a [u8],
276 literal: &[u8],
277 ) -> Result<&'a [u8], error::ParseFromDescription> {
278 input
279 .strip_prefix(literal)
280 .ok_or(error::ParseFromDescription::InvalidLiteral)
281 }
282
283 pub fn parse_component<'a>(
286 &mut self,
287 input: &'a [u8],
288 component: Component,
289 ) -> Result<&'a [u8], error::ParseFromDescription> {
290 use error::ParseFromDescription::InvalidComponent;
291
292 match component {
293 Component::Day(modifiers) => parse_day(input, modifiers)
294 .and_then(|parsed| parsed.consume_value(|value| self.set_day(value)))
295 .ok_or(InvalidComponent("day")),
296 Component::Month(modifiers) => parse_month(input, modifiers)
297 .and_then(|parsed| parsed.consume_value(|value| self.set_month(value)))
298 .ok_or(InvalidComponent("month")),
299 Component::Ordinal(modifiers) => parse_ordinal(input, modifiers)
300 .and_then(|parsed| parsed.consume_value(|value| self.set_ordinal(value)))
301 .ok_or(InvalidComponent("ordinal")),
302 Component::Weekday(modifiers) => parse_weekday(input, modifiers)
303 .and_then(|parsed| parsed.consume_value(|value| self.set_weekday(value)))
304 .ok_or(InvalidComponent("weekday")),
305 Component::WeekNumber(modifiers) => {
306 let ParsedItem(remaining, value) =
307 parse_week_number(input, modifiers).ok_or(InvalidComponent("week number"))?;
308 match modifiers.repr {
309 modifier::WeekNumberRepr::Iso => {
310 NonZero::new(value).and_then(|value| self.set_iso_week_number(value))
311 }
312 modifier::WeekNumberRepr::Sunday => self.set_sunday_week_number(value),
313 modifier::WeekNumberRepr::Monday => self.set_monday_week_number(value),
314 }
315 .ok_or(InvalidComponent("week number"))?;
316 Ok(remaining)
317 }
318 Component::Year(modifiers) => {
319 let ParsedItem(remaining, (value, is_negative)) =
320 parse_year(input, modifiers).ok_or(InvalidComponent("year"))?;
321 match (modifiers.iso_week_based, modifiers.repr) {
322 (false, modifier::YearRepr::Full) => self.set_year(value),
323 (false, modifier::YearRepr::Century) => {
324 self.set_year_century(value.truncate(), is_negative)
325 }
326 (false, modifier::YearRepr::LastTwo) => {
327 self.set_year_last_two(value.cast_unsigned().truncate())
328 }
329 (true, modifier::YearRepr::Full) => self.set_iso_year(value),
330 (true, modifier::YearRepr::Century) => {
331 self.set_iso_year_century(value.truncate(), is_negative)
332 }
333 (true, modifier::YearRepr::LastTwo) => {
334 self.set_iso_year_last_two(value.cast_unsigned().truncate())
335 }
336 }
337 .ok_or(InvalidComponent("year"))?;
338 Ok(remaining)
339 }
340 Component::Hour(modifiers) => {
341 let ParsedItem(remaining, value) =
342 parse_hour(input, modifiers).ok_or(InvalidComponent("hour"))?;
343 if modifiers.is_12_hour_clock {
344 NonZero::new(value).and_then(|value| self.set_hour_12(value))
345 } else {
346 self.set_hour_24(value)
347 }
348 .ok_or(InvalidComponent("hour"))?;
349 Ok(remaining)
350 }
351 Component::Minute(modifiers) => parse_minute(input, modifiers)
352 .and_then(|parsed| parsed.consume_value(|value| self.set_minute(value)))
353 .ok_or(InvalidComponent("minute")),
354 Component::Period(modifiers) => parse_period(input, modifiers)
355 .and_then(|parsed| {
356 parsed.consume_value(|value| self.set_hour_12_is_pm(value == Period::Pm))
357 })
358 .ok_or(InvalidComponent("period")),
359 Component::Second(modifiers) => parse_second(input, modifiers)
360 .and_then(|parsed| parsed.consume_value(|value| self.set_second(value)))
361 .ok_or(InvalidComponent("second")),
362 Component::Subsecond(modifiers) => parse_subsecond(input, modifiers)
363 .and_then(|parsed| parsed.consume_value(|value| self.set_subsecond(value)))
364 .ok_or(InvalidComponent("subsecond")),
365 Component::OffsetHour(modifiers) => parse_offset_hour(input, modifiers)
366 .and_then(|parsed| {
367 parsed.consume_value(|(value, is_negative)| {
368 self.set_offset_hour(value)?;
369 self.offset_is_negative = is_negative;
370 Some(())
371 })
372 })
373 .ok_or(InvalidComponent("offset hour")),
374 Component::OffsetMinute(modifiers) => parse_offset_minute(input, modifiers)
375 .and_then(|parsed| {
376 parsed.consume_value(|value| self.set_offset_minute_signed(value))
377 })
378 .ok_or(InvalidComponent("offset minute")),
379 Component::OffsetSecond(modifiers) => parse_offset_second(input, modifiers)
380 .and_then(|parsed| {
381 parsed.consume_value(|value| self.set_offset_second_signed(value))
382 })
383 .ok_or(InvalidComponent("offset second")),
384 Component::Ignore(modifiers) => parse_ignore(input, modifiers)
385 .map(ParsedItem::<()>::into_inner)
386 .ok_or(InvalidComponent("ignore")),
387 Component::UnixTimestamp(modifiers) => parse_unix_timestamp(input, modifiers)
388 .and_then(|parsed| {
389 parsed.consume_value(|value| self.set_unix_timestamp_nanos(value))
390 })
391 .ok_or(InvalidComponent("unix_timestamp")),
392 Component::End(modifiers) => parse_end(input, modifiers)
393 .map(ParsedItem::<()>::into_inner)
394 .ok_or(error::ParseFromDescription::UnexpectedTrailingCharacters),
395 }
396 }
397}
398
399impl Parsed {
401 #[inline]
403 pub const fn year(&self) -> Option<i32> {
404 self.year.get_primitive()
405 }
406
407 #[inline]
412 pub const fn year_century(&self) -> Option<i16> {
413 self.year_century.get_primitive()
414 }
415
416 #[inline]
421 pub const fn year_century_is_negative(&self) -> Option<bool> {
422 match self.year_century() {
423 Some(_) => Some(self.year_century_is_negative),
424 None => None,
425 }
426 }
427
428 #[inline]
430 pub const fn year_last_two(&self) -> Option<u8> {
431 self.year_last_two.get_primitive()
432 }
433
434 #[inline]
436 pub const fn iso_year(&self) -> Option<i32> {
437 self.iso_year.get_primitive()
438 }
439
440 #[inline]
445 pub const fn iso_year_century(&self) -> Option<i16> {
446 self.iso_year_century.get_primitive()
447 }
448
449 #[inline]
454 pub const fn iso_year_century_is_negative(&self) -> Option<bool> {
455 match self.iso_year_century() {
456 Some(_) => Some(self.iso_year_century_is_negative),
457 None => None,
458 }
459 }
460
461 #[inline]
463 pub const fn iso_year_last_two(&self) -> Option<u8> {
464 self.iso_year_last_two.get_primitive()
465 }
466
467 #[inline]
469 pub const fn month(&self) -> Option<Month> {
470 self.month
471 }
472
473 #[inline]
475 pub const fn sunday_week_number(&self) -> Option<u8> {
476 self.sunday_week_number.get_primitive()
477 }
478
479 #[inline]
481 pub const fn monday_week_number(&self) -> Option<u8> {
482 self.monday_week_number.get_primitive()
483 }
484
485 #[inline]
487 pub const fn iso_week_number(&self) -> Option<NonZero<u8>> {
488 NonZero::new(const_try_opt!(self.iso_week_number.get_primitive()))
489 }
490
491 #[inline]
493 pub const fn weekday(&self) -> Option<Weekday> {
494 self.weekday
495 }
496
497 #[inline]
499 pub const fn ordinal(&self) -> Option<NonZero<u16>> {
500 NonZero::new(const_try_opt!(self.ordinal.get_primitive()))
501 }
502
503 #[inline]
505 pub const fn day(&self) -> Option<NonZero<u8>> {
506 NonZero::new(const_try_opt!(self.day.get_primitive()))
507 }
508
509 #[inline]
511 pub const fn hour_24(&self) -> Option<u8> {
512 self.hour_24.get_primitive()
513 }
514
515 #[inline]
517 pub const fn hour_12(&self) -> Option<NonZero<u8>> {
518 NonZero::new(const_try_opt!(self.hour_12.get_primitive()))
519 }
520
521 #[inline]
523 pub const fn hour_12_is_pm(&self) -> Option<bool> {
524 self.hour_12_is_pm
525 }
526
527 #[inline]
529 pub const fn minute(&self) -> Option<u8> {
530 self.minute.get_primitive()
531 }
532
533 #[inline]
535 pub const fn second(&self) -> Option<u8> {
536 self.second.get_primitive()
537 }
538
539 #[inline]
541 pub const fn subsecond(&self) -> Option<u32> {
542 self.subsecond.get_primitive()
543 }
544
545 #[inline]
547 pub const fn offset_hour(&self) -> Option<i8> {
548 self.offset_hour.get_primitive()
549 }
550
551 #[doc(hidden)]
553 #[deprecated(since = "0.3.8", note = "use `parsed.offset_minute_signed()` instead")]
554 #[inline]
555 pub const fn offset_minute(&self) -> Option<u8> {
556 Some(const_try_opt!(self.offset_minute_signed()).unsigned_abs())
557 }
558
559 #[inline]
561 pub const fn offset_minute_signed(&self) -> Option<i8> {
562 match (self.offset_minute.get_primitive(), self.offset_is_negative) {
563 (Some(offset_minute), true) => Some(-offset_minute),
564 (Some(offset_minute), _) => Some(offset_minute),
565 (None, _) => None,
566 }
567 }
568
569 #[doc(hidden)]
571 #[deprecated(since = "0.3.8", note = "use `parsed.offset_second_signed()` instead")]
572 #[inline]
573 pub const fn offset_second(&self) -> Option<u8> {
574 Some(const_try_opt!(self.offset_second_signed()).unsigned_abs())
575 }
576
577 #[inline]
579 pub const fn offset_second_signed(&self) -> Option<i8> {
580 match (self.offset_second.get_primitive(), self.offset_is_negative) {
581 (Some(offset_second), true) => Some(-offset_second),
582 (Some(offset_second), _) => Some(offset_second),
583 (None, _) => None,
584 }
585 }
586
587 #[inline]
589 pub const fn unix_timestamp_nanos(&self) -> Option<i128> {
590 self.unix_timestamp_nanos.get_primitive()
591 }
592}
593
594macro_rules! setters {
596 ($($name:ident $setter:ident $builder:ident $type:ty;)*) => {$(
597 #[doc = concat!("Set the `", stringify!($name), "` component.")]
598 #[inline]
599 pub const fn $setter(&mut self, value: $type) -> Option<()> {
600 match self.$builder(value) {
601 Some(value) => {
602 *self = value;
603 Some(())
604 },
605 None => None,
606 }
607 }
608 )*};
609}
610
611impl Parsed {
616 setters! {
617 year set_year with_year i32;
618 }
619
620 #[inline]
625 pub const fn set_year_century(&mut self, value: i16, is_negative: bool) -> Option<()> {
626 self.year_century = OptionRangedI16::Some(const_try_opt!(RangedI16::new(value)));
627 if value != 0 {
628 self.year_century_is_negative = value.is_negative();
629 } else {
630 self.year_century_is_negative = is_negative;
631 }
632 Some(())
633 }
634
635 setters! {
636 year_last_two set_year_last_two with_year_last_two u8;
637 iso_year set_iso_year with_iso_year i32;
638 iso_year_last_two set_iso_year_last_two with_iso_year_last_two u8;
639 }
640
641 #[inline]
646 pub const fn set_iso_year_century(&mut self, value: i16, is_negative: bool) -> Option<()> {
647 self.iso_year_century = OptionRangedI16::Some(const_try_opt!(RangedI16::new(value)));
648 if value != 0 {
649 self.iso_year_century_is_negative = value.is_negative();
650 } else {
651 self.iso_year_century_is_negative = is_negative;
652 }
653 Some(())
654 }
655
656 setters! {
657 month set_month with_month Month;
658 sunday_week_number set_sunday_week_number with_sunday_week_number u8;
659 monday_week_number set_monday_week_number with_monday_week_number u8;
660 iso_week_number set_iso_week_number with_iso_week_number NonZero<u8>;
661 weekday set_weekday with_weekday Weekday;
662 ordinal set_ordinal with_ordinal NonZero<u16>;
663 day set_day with_day NonZero<u8>;
664 hour_24 set_hour_24 with_hour_24 u8;
665 hour_12 set_hour_12 with_hour_12 NonZero<u8>;
666 hour_12_is_pm set_hour_12_is_pm with_hour_12_is_pm bool;
667 minute set_minute with_minute u8;
668 second set_second with_second u8;
669 subsecond set_subsecond with_subsecond u32;
670 offset_hour set_offset_hour with_offset_hour i8;
671 offset_minute set_offset_minute_signed with_offset_minute_signed i8;
672 offset_second set_offset_second_signed with_offset_second_signed i8;
673 unix_timestamp_nanos set_unix_timestamp_nanos with_unix_timestamp_nanos i128;
674 }
675
676 #[doc(hidden)]
678 #[deprecated(
679 since = "0.3.8",
680 note = "use `parsed.set_offset_minute_signed()` instead"
681 )]
682 #[inline]
683 pub const fn set_offset_minute(&mut self, value: u8) -> Option<()> {
684 if value > i8::MAX.cast_unsigned() {
685 None
686 } else {
687 self.set_offset_minute_signed(value.cast_signed())
688 }
689 }
690
691 #[doc(hidden)]
693 #[deprecated(
694 since = "0.3.8",
695 note = "use `parsed.set_offset_second_signed()` instead"
696 )]
697 #[inline]
698 pub const fn set_offset_second(&mut self, value: u8) -> Option<()> {
699 if value > i8::MAX.cast_unsigned() {
700 None
701 } else {
702 self.set_offset_second_signed(value.cast_signed())
703 }
704 }
705}
706
707impl Parsed {
712 #[inline]
714 pub const fn with_year(mut self, value: i32) -> Option<Self> {
715 self.year = OptionRangedI32::Some(const_try_opt!(RangedI32::new(value)));
716 Some(self)
717 }
718
719 #[inline]
724 pub const fn with_year_century(mut self, value: i16, is_negative: bool) -> Option<Self> {
725 self.year_century = OptionRangedI16::Some(const_try_opt!(RangedI16::new(value)));
726 if value != 0 {
727 self.year_century_is_negative = value.is_negative();
728 } else {
729 self.year_century_is_negative = is_negative;
730 }
731 Some(self)
732 }
733
734 #[inline]
736 pub const fn with_year_last_two(mut self, value: u8) -> Option<Self> {
737 self.year_last_two = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
738 Some(self)
739 }
740
741 #[inline]
743 pub const fn with_iso_year(mut self, value: i32) -> Option<Self> {
744 self.iso_year = OptionRangedI32::Some(const_try_opt!(RangedI32::new(value)));
745 Some(self)
746 }
747
748 #[inline]
753 pub const fn with_iso_year_century(mut self, value: i16, is_negative: bool) -> Option<Self> {
754 self.iso_year_century = OptionRangedI16::Some(const_try_opt!(RangedI16::new(value)));
755 if value != 0 {
756 self.iso_year_century_is_negative = value.is_negative();
757 } else {
758 self.iso_year_century_is_negative = is_negative;
759 }
760 Some(self)
761 }
762
763 #[inline]
765 pub const fn with_iso_year_last_two(mut self, value: u8) -> Option<Self> {
766 self.iso_year_last_two = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
767 Some(self)
768 }
769
770 #[inline]
772 pub const fn with_month(mut self, value: Month) -> Option<Self> {
773 self.month = Some(value);
774 Some(self)
775 }
776
777 #[inline]
779 pub const fn with_sunday_week_number(mut self, value: u8) -> Option<Self> {
780 self.sunday_week_number = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
781 Some(self)
782 }
783
784 #[inline]
786 pub const fn with_monday_week_number(mut self, value: u8) -> Option<Self> {
787 self.monday_week_number = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
788 Some(self)
789 }
790
791 #[inline]
793 pub const fn with_iso_week_number(mut self, value: NonZero<u8>) -> Option<Self> {
794 self.iso_week_number = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value.get())));
795 Some(self)
796 }
797
798 #[inline]
800 pub const fn with_weekday(mut self, value: Weekday) -> Option<Self> {
801 self.weekday = Some(value);
802 Some(self)
803 }
804
805 #[inline]
807 pub const fn with_ordinal(mut self, value: NonZero<u16>) -> Option<Self> {
808 self.ordinal = OptionRangedU16::Some(const_try_opt!(RangedU16::new(value.get())));
809 Some(self)
810 }
811
812 #[inline]
814 pub const fn with_day(mut self, value: NonZero<u8>) -> Option<Self> {
815 self.day = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value.get())));
816 Some(self)
817 }
818
819 #[inline]
821 pub const fn with_hour_24(mut self, value: u8) -> Option<Self> {
822 self.hour_24 = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
823 Some(self)
824 }
825
826 #[inline]
828 pub const fn with_hour_12(mut self, value: NonZero<u8>) -> Option<Self> {
829 self.hour_12 = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value.get())));
830 Some(self)
831 }
832
833 #[inline]
835 pub const fn with_hour_12_is_pm(mut self, value: bool) -> Option<Self> {
836 self.hour_12_is_pm = Some(value);
837 Some(self)
838 }
839
840 #[inline]
842 pub const fn with_minute(mut self, value: u8) -> Option<Self> {
843 self.minute = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
844 Some(self)
845 }
846
847 #[inline]
849 pub const fn with_second(mut self, value: u8) -> Option<Self> {
850 self.second = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
851 Some(self)
852 }
853
854 #[inline]
856 pub const fn with_subsecond(mut self, value: u32) -> Option<Self> {
857 self.subsecond = OptionRangedU32::Some(const_try_opt!(RangedU32::new(value)));
858 Some(self)
859 }
860
861 #[inline]
863 pub const fn with_offset_hour(mut self, value: i8) -> Option<Self> {
864 self.offset_hour = OptionRangedI8::Some(const_try_opt!(RangedI8::new(value)));
865 Some(self)
866 }
867
868 #[doc(hidden)]
870 #[deprecated(
871 since = "0.3.8",
872 note = "use `parsed.with_offset_minute_signed()` instead"
873 )]
874 #[inline]
875 pub const fn with_offset_minute(self, value: u8) -> Option<Self> {
876 if value > i8::MAX.cast_unsigned() {
877 None
878 } else {
879 self.with_offset_minute_signed(value.cast_signed())
880 }
881 }
882
883 #[inline]
885 pub const fn with_offset_minute_signed(mut self, value: i8) -> Option<Self> {
886 self.offset_minute = OptionRangedI8::Some(const_try_opt!(RangedI8::new(value)));
887 Some(self)
888 }
889
890 #[doc(hidden)]
892 #[deprecated(
893 since = "0.3.8",
894 note = "use `parsed.with_offset_second_signed()` instead"
895 )]
896 #[inline]
897 pub const fn with_offset_second(self, value: u8) -> Option<Self> {
898 if value > i8::MAX.cast_unsigned() {
899 None
900 } else {
901 self.with_offset_second_signed(value.cast_signed())
902 }
903 }
904
905 #[inline]
907 pub const fn with_offset_second_signed(mut self, value: i8) -> Option<Self> {
908 self.offset_second = OptionRangedI8::Some(const_try_opt!(RangedI8::new(value)));
909 Some(self)
910 }
911
912 #[inline]
914 pub const fn with_unix_timestamp_nanos(mut self, value: i128) -> Option<Self> {
915 self.unix_timestamp_nanos = OptionRangedI128::Some(const_try_opt!(RangedI128::new(value)));
916 Some(self)
917 }
918}
919
920impl TryFrom<Parsed> for Date {
921 type Error = error::TryFromParsed;
922
923 #[inline]
924 fn try_from(mut parsed: Parsed) -> Result<Self, Self::Error> {
925 macro_rules! match_ {
927 (_ => $catch_all:expr $(,)?) => {
928 $catch_all
929 };
930 (($($name:ident),* $(,)?) => $arm:expr, $($rest:tt)*) => {
931 if let ($(Some($name)),*) = ($(parsed.$name()),*) {
932 $arm
933 } else {
934 match_!($($rest)*)
935 }
936 };
937 }
938
939 #[inline]
942 const fn adjustment(year: i32) -> i16 {
943 match unsafe { Date::__from_ordinal_date_unchecked(year, 1) }.weekday() {
945 Weekday::Monday => 7,
946 Weekday::Tuesday => 1,
947 Weekday::Wednesday => 2,
948 Weekday::Thursday => 3,
949 Weekday::Friday => 4,
950 Weekday::Saturday => 5,
951 Weekday::Sunday => 6,
952 }
953 }
954
955 if let (None, Some(century), Some(is_negative), Some(last_two)) = (
958 parsed.year(),
959 parsed.year_century(),
960 parsed.year_century_is_negative(),
961 parsed.year_last_two(),
962 ) {
963 let year = if is_negative {
964 100 * century.extend::<i32>() - last_two.cast_signed().extend::<i32>()
965 } else {
966 100 * century.extend::<i32>() + last_two.cast_signed().extend::<i32>()
967 };
968 parsed.year = OptionRangedI32::from(RangedI32::new(year));
969 }
970 if let (None, Some(century), Some(is_negative), Some(last_two)) = (
971 parsed.iso_year(),
972 parsed.iso_year_century(),
973 parsed.iso_year_century_is_negative(),
974 parsed.iso_year_last_two(),
975 ) {
976 let iso_year = if is_negative {
977 100 * century.extend::<i32>() - last_two.cast_signed().extend::<i32>()
978 } else {
979 100 * century.extend::<i32>() + last_two.cast_signed().extend::<i32>()
980 };
981 parsed.iso_year = OptionRangedI32::from(RangedI32::new(iso_year));
982 }
983
984 match_! {
985 (year, ordinal) => Ok(Self::from_ordinal_date(year, ordinal.get())?),
986 (year, month, day) => Ok(Self::from_calendar_date(year, month, day.get())?),
987 (iso_year, iso_week_number, weekday) => Ok(Self::from_iso_week_date(
988 iso_year,
989 iso_week_number.get(),
990 weekday,
991 )?),
992 (year, sunday_week_number, weekday) => Ok(Self::from_ordinal_date(
993 year,
994 (sunday_week_number.cast_signed().extend::<i16>() * 7
995 + weekday.number_days_from_sunday().cast_signed().extend::<i16>()
996 - adjustment(year)
997 + 1).cast_unsigned(),
998 )?),
999 (year, monday_week_number, weekday) => Ok(Self::from_ordinal_date(
1000 year,
1001 (monday_week_number.cast_signed().extend::<i16>() * 7
1002 + weekday.number_days_from_monday().cast_signed().extend::<i16>()
1003 - adjustment(year)
1004 + 1).cast_unsigned(),
1005 )?),
1006 _ => Err(InsufficientInformation),
1007 }
1008 }
1009}
1010
1011impl TryFrom<Parsed> for Time {
1012 type Error = error::TryFromParsed;
1013
1014 #[inline]
1015 fn try_from(parsed: Parsed) -> Result<Self, Self::Error> {
1016 let hour = match (parsed.hour_24(), parsed.hour_12(), parsed.hour_12_is_pm()) {
1017 (Some(hour), _, _) => hour,
1018 (_, Some(hour), Some(false)) if hour.get() == 12 => 0,
1019 (_, Some(hour), Some(true)) if hour.get() == 12 => 12,
1020 (_, Some(hour), Some(false)) => hour.get(),
1021 (_, Some(hour), Some(true)) => hour.get() + 12,
1022 _ => return Err(InsufficientInformation),
1023 };
1024
1025 if parsed.hour_24().is_none()
1026 && parsed.hour_12().is_some()
1027 && parsed.hour_12_is_pm().is_some()
1028 && parsed.minute().is_none()
1029 && parsed.second().is_none()
1030 && parsed.subsecond().is_none()
1031 {
1032 return Ok(Self::from_hms_nano(hour, 0, 0, 0)?);
1033 }
1034
1035 match (parsed.minute(), parsed.second(), parsed.subsecond()) {
1037 (None, None, None) => Ok(Self::from_hms_nano(hour, 0, 0, 0)?),
1038 (Some(minute), None, None) => Ok(Self::from_hms_nano(hour, minute, 0, 0)?),
1039 (Some(minute), Some(second), None) => Ok(Self::from_hms_nano(hour, minute, second, 0)?),
1040 (Some(minute), Some(second), Some(subsecond)) => {
1041 Ok(Self::from_hms_nano(hour, minute, second, subsecond)?)
1042 }
1043 _ => Err(InsufficientInformation),
1044 }
1045 }
1046}
1047
1048#[inline]
1049fn utc_offset_try_from_parsed<const REQUIRED: bool>(
1050 parsed: Parsed,
1051) -> Result<UtcOffset, error::TryFromParsed> {
1052 let hour = match (REQUIRED, parsed.offset_hour()) {
1053 (true, None) => return Err(InsufficientInformation),
1055 (false, None) => return Ok(UtcOffset::UTC),
1058 (_, Some(hour)) => hour,
1060 };
1061 let minute = parsed.offset_minute_signed();
1062 let second = minute.and_then(|_| parsed.offset_second_signed());
1064
1065 let minute = minute.unwrap_or(0);
1066 let second = second.unwrap_or(0);
1067
1068 UtcOffset::from_hms(hour, minute, second).map_err(Into::into)
1069}
1070
1071impl TryFrom<Parsed> for UtcOffset {
1072 type Error = error::TryFromParsed;
1073
1074 #[inline]
1075 fn try_from(parsed: Parsed) -> Result<Self, Self::Error> {
1076 utc_offset_try_from_parsed::<true>(parsed)
1077 }
1078}
1079
1080impl TryFrom<Parsed> for PrimitiveDateTime {
1081 type Error = error::TryFromParsed;
1082
1083 #[inline]
1084 fn try_from(parsed: Parsed) -> Result<Self, Self::Error> {
1085 Ok(Self::new(parsed.try_into()?, parsed.try_into()?))
1086 }
1087}
1088
1089impl TryFrom<Parsed> for UtcDateTime {
1090 type Error = error::TryFromParsed;
1091
1092 #[inline]
1093 fn try_from(mut parsed: Parsed) -> Result<Self, Self::Error> {
1094 if let Some(timestamp) = parsed.unix_timestamp_nanos() {
1095 let mut value = Self::from_unix_timestamp_nanos(timestamp)?;
1096 if let Some(subsecond) = parsed.subsecond() {
1097 value = value.replace_nanosecond(subsecond)?;
1098 }
1099 return Ok(value);
1100 }
1101
1102 let leap_second_input = if parsed.leap_second_allowed && parsed.second() == Some(60) {
1106 if parsed.set_second(59).is_none() {
1107 bug!("59 is a valid second");
1108 }
1109 if parsed.set_subsecond(999_999_999).is_none() {
1110 bug!("999_999_999 is a valid subsecond");
1111 }
1112 true
1113 } else {
1114 false
1115 };
1116
1117 let dt = OffsetDateTime::new_in_offset(
1118 Date::try_from(parsed)?,
1119 Time::try_from(parsed)?,
1120 utc_offset_try_from_parsed::<false>(parsed)?,
1121 )
1122 .to_utc();
1123
1124 if leap_second_input && !dt.is_valid_leap_second_stand_in() {
1125 return Err(error::TryFromParsed::ComponentRange(
1126 error::ComponentRange::conditional("second"),
1127 ));
1128 }
1129 Ok(dt)
1130 }
1131}
1132
1133impl TryFrom<Parsed> for OffsetDateTime {
1134 type Error = error::TryFromParsed;
1135
1136 #[inline]
1137 fn try_from(mut parsed: Parsed) -> Result<Self, Self::Error> {
1138 if let Some(timestamp) = parsed.unix_timestamp_nanos() {
1139 let mut value = Self::from_unix_timestamp_nanos(timestamp)?;
1140 if let Some(subsecond) = parsed.subsecond() {
1141 value = value.replace_nanosecond(subsecond)?;
1142 }
1143 return Ok(value);
1144 }
1145
1146 let leap_second_input = if parsed.leap_second_allowed && parsed.second() == Some(60) {
1150 if parsed.set_second(59).is_none() {
1151 bug!("59 is a valid second");
1152 }
1153 if parsed.set_subsecond(999_999_999).is_none() {
1154 bug!("999_999_999 is a valid subsecond");
1155 }
1156 true
1157 } else {
1158 false
1159 };
1160
1161 let dt = Self::new_in_offset(
1162 Date::try_from(parsed)?,
1163 Time::try_from(parsed)?,
1164 UtcOffset::try_from(parsed)?,
1165 );
1166
1167 if leap_second_input && !dt.is_valid_leap_second_stand_in() {
1168 return Err(error::TryFromParsed::ComponentRange(
1169 error::ComponentRange::conditional("second"),
1170 ));
1171 }
1172 Ok(dt)
1173 }
1174}