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;
13#[cfg(feature = "alloc")]
14use crate::format_description::OwnedFormatItem;
15use crate::format_description::format_description_v3::FormatDescriptionV3Inner;
16use crate::format_description::{BorrowedFormatItem, Component, Period};
17use crate::internal_macros::{bug, const_try_opt};
18use crate::parsing::ParsedItem;
19use crate::parsing::component::{
20 parse_calendar_year_century_extended_range, parse_calendar_year_century_standard_range,
21 parse_calendar_year_full_extended_range, parse_calendar_year_full_standard_range,
22 parse_calendar_year_last_two, parse_day, parse_end, parse_hour_12, parse_hour_24, parse_ignore,
23 parse_iso_year_century_extended_range, parse_iso_year_century_standard_range,
24 parse_iso_year_full_extended_range, parse_iso_year_full_standard_range,
25 parse_iso_year_last_two, parse_minute, parse_month_long, parse_month_numerical,
26 parse_month_short, parse_offset_hour, parse_offset_minute, parse_offset_second, parse_ordinal,
27 parse_period, parse_second, parse_subsecond, parse_unix_timestamp_microsecond,
28 parse_unix_timestamp_millisecond, parse_unix_timestamp_nanosecond, parse_unix_timestamp_second,
29 parse_week_number_iso, parse_week_number_monday, parse_week_number_sunday, parse_weekday_long,
30 parse_weekday_monday, parse_weekday_short, parse_weekday_sunday,
31};
32use crate::unit::{Day, Hour, Minute, Nanosecond, Second};
33use crate::{
34 Date, Month, OffsetDateTime, PrimitiveDateTime, Time, Timestamp, UtcDateTime, UtcOffset,
35 Weekday, error,
36};
37
38mod sealed {
40 use super::*;
41
42 pub trait AnyFormatItem {
44 fn parse_item<'a>(
46 &self,
47 parsed: &mut Parsed,
48 input: &'a [u8],
49 ) -> Result<&'a [u8], error::ParseFromDescription>;
50 }
51}
52
53impl sealed::AnyFormatItem for BorrowedFormatItem<'_> {
54 #[inline(always)]
55 fn parse_item<'a>(
56 &self,
57 parsed: &mut Parsed,
58 input: &'a [u8],
59 ) -> Result<&'a [u8], error::ParseFromDescription> {
60 match self {
61 #[expect(deprecated)]
62 Self::Literal(literal) => Parsed::parse_literal(input, literal),
63 Self::StringLiteral(literal) => Parsed::parse_literal(input, literal.as_bytes()),
64 Self::Component(component) => parsed.parse_component(input, *component),
65 Self::Compound(compound) => parsed.parse_items(input, compound),
66 Self::Optional(item) => parsed.parse_item(input, *item).or(Ok(input)),
67 Self::First(items) => {
68 let mut first_err = None;
69
70 for item in items.iter() {
71 match parsed.parse_item(input, item) {
72 Ok(remaining_input) => return Ok(remaining_input),
73 Err(err) if first_err.is_none() => first_err = Some(err),
74 Err(_) => {}
75 }
76 }
77
78 match first_err {
79 Some(err) => Err(err),
80 None => Ok(input),
83 }
84 }
85 }
86 }
87}
88
89#[cfg(feature = "alloc")]
90impl sealed::AnyFormatItem for OwnedFormatItem {
91 #[inline]
92 fn parse_item<'a>(
93 &self,
94 parsed: &mut Parsed,
95 input: &'a [u8],
96 ) -> Result<&'a [u8], error::ParseFromDescription> {
97 match self {
98 #[expect(deprecated)]
99 Self::Literal(literal) => Parsed::parse_literal(input, literal),
100 Self::StringLiteral(literal) => Parsed::parse_literal(input, literal.as_bytes()),
101 Self::Component(component) => parsed.parse_component(input, *component),
102 Self::Compound(compound) => parsed.parse_items(input, compound),
103 Self::Optional(item) => parsed.parse_item(input, item.as_ref()).or(Ok(input)),
104 Self::First(items) => {
105 let mut first_err = None;
106
107 for item in items.iter() {
108 match parsed.parse_item(input, item) {
109 Ok(remaining_input) => return Ok(remaining_input),
110 Err(err) if first_err.is_none() => first_err = Some(err),
111 Err(_) => {}
112 }
113 }
114
115 match first_err {
116 Some(err) => Err(err),
117 None => Ok(input),
120 }
121 }
122 }
123 }
124}
125
126#[derive(Debug, Clone, Copy)]
133pub struct Parsed {
134 year: Option_ri32<{ MIN_YEAR }, { MAX_YEAR }>,
136 year_century: Option_ri16<{ (MIN_YEAR / 100) as i16 }, { (MAX_YEAR / 100) as i16 }>,
138 year_last_two: Option_ru8<0, 99>,
140 iso_year: Option_ri32<{ MIN_YEAR }, { MAX_YEAR }>,
142 iso_year_century: Option_ri16<{ (MIN_YEAR / 100) as i16 }, { (MAX_YEAR / 100) as i16 }>,
144 iso_year_last_two: Option_ru8<0, 99>,
146 month: Option<Month>,
148 sunday_week_number: Option_ru8<0, 53>,
150 monday_week_number: Option_ru8<0, 53>,
152 iso_week_number: Option_ru8<1, 53>,
154 weekday: Option<Weekday>,
156 ordinal: Option_ru16<1, 366>,
158 day: Option_ru8<1, 31>,
160 hour_24: Option_ru8<0, { Hour::per_t::<u8>(Day) - 1 }>,
162 hour_12: Option_ru8<1, 12>,
165 hour_12_is_pm: Option<bool>,
167 minute: Option_ru8<0, { Minute::per_t::<u8>(Hour) - 1 }>,
169 second: Option_ru8<0, { Second::per_t::<u8>(Minute) }>,
172 subsecond: Option_ru32<0, { Nanosecond::per_t::<u32>(Second) - 1 }>,
174 offset_hour: Option_ri8<-25, 25>,
176 offset_minute:
178 Option_ri8<{ -Minute::per_t::<i8>(Hour) + 1 }, { Minute::per_t::<i8>(Hour) - 1 }>,
179 offset_second:
181 Option_ri8<{ -Second::per_t::<i8>(Minute) + 1 }, { Second::per_t::<i8>(Minute) - 1 }>,
182 unix_timestamp_nanos: Option_ri128<
184 {
185 OffsetDateTime::new_in_offset(Date::MIN, Time::MIDNIGHT, UtcOffset::UTC)
186 .unix_timestamp_nanos()
187 },
188 {
189 OffsetDateTime::new_in_offset(Date::MAX, Time::MAX, UtcOffset::UTC)
190 .unix_timestamp_nanos()
191 },
192 >,
193 offset_is_negative: bool,
196 year_century_is_negative: bool,
199 iso_year_century_is_negative: bool,
202 pub(super) leap_second_allowed: bool,
205}
206
207impl Default for Parsed {
208 #[inline]
209 fn default() -> Self {
210 Self::new()
211 }
212}
213
214impl Parsed {
215 #[inline]
217 pub const fn new() -> Self {
218 Self {
219 year: Option_ri32::None,
220 year_century: Option_ri16::None,
221 year_last_two: Option_ru8::None,
222 iso_year: Option_ri32::None,
223 iso_year_century: Option_ri16::None,
224 iso_year_last_two: Option_ru8::None,
225 month: None,
226 sunday_week_number: Option_ru8::None,
227 monday_week_number: Option_ru8::None,
228 iso_week_number: Option_ru8::None,
229 weekday: None,
230 ordinal: Option_ru16::None,
231 day: Option_ru8::None,
232 hour_24: Option_ru8::None,
233 hour_12: Option_ru8::None,
234 hour_12_is_pm: None,
235 minute: Option_ru8::None,
236 second: Option_ru8::None,
237 subsecond: Option_ru32::None,
238 offset_hour: Option_ri8::None,
239 offset_minute: Option_ri8::None,
240 offset_second: Option_ri8::None,
241 unix_timestamp_nanos: Option_ri128::None,
242 offset_is_negative: false,
243 year_century_is_negative: false,
244 iso_year_century_is_negative: false,
245 leap_second_allowed: false,
246 }
247 }
248
249 #[inline]
252 pub(crate) fn parse_v3_inner<'a>(
253 &mut self,
254 mut input: &'a [u8],
255 format_description: &FormatDescriptionV3Inner<'_>,
256 ) -> Result<&'a [u8], error::ParseFromDescription> {
257 use error::ParseFromDescription::InvalidComponent;
258
259 match format_description {
260 FormatDescriptionV3Inner::Day(modifiers) => parse_day(input, *modifiers)
261 .and_then(|parsed| parsed.consume_value(|value| self.set_day(value)))
262 .ok_or(InvalidComponent("day")),
263 FormatDescriptionV3Inner::MonthShort(modifiers) => parse_month_short(input, *modifiers)
264 .and_then(|parsed| parsed.consume_value(|value| self.set_month(value)))
265 .ok_or(InvalidComponent("month")),
266 FormatDescriptionV3Inner::MonthLong(modifiers) => parse_month_long(input, *modifiers)
267 .and_then(|parsed| parsed.consume_value(|value| self.set_month(value)))
268 .ok_or(InvalidComponent("month")),
269 FormatDescriptionV3Inner::MonthNumerical(modifiers) => {
270 parse_month_numerical(input, *modifiers)
271 .and_then(|parsed| parsed.consume_value(|value| self.set_month(value)))
272 .ok_or(InvalidComponent("month"))
273 }
274 FormatDescriptionV3Inner::Ordinal(modifiers) => parse_ordinal(input, *modifiers)
275 .and_then(|parsed| parsed.consume_value(|value| self.set_ordinal(value)))
276 .ok_or(InvalidComponent("ordinal")),
277 FormatDescriptionV3Inner::WeekdayShort(modifiers) => {
278 parse_weekday_short(input, *modifiers)
279 .and_then(|parsed| parsed.consume_value(|value| self.set_weekday(value)))
280 .ok_or(InvalidComponent("weekday"))
281 }
282 FormatDescriptionV3Inner::WeekdayLong(modifiers) => {
283 parse_weekday_long(input, *modifiers)
284 .and_then(|parsed| parsed.consume_value(|value| self.set_weekday(value)))
285 .ok_or(InvalidComponent("weekday"))
286 }
287 FormatDescriptionV3Inner::WeekdaySunday(modifiers) => {
288 parse_weekday_sunday(input, *modifiers)
289 .and_then(|parsed| parsed.consume_value(|value| self.set_weekday(value)))
290 .ok_or(InvalidComponent("weekday"))
291 }
292 FormatDescriptionV3Inner::WeekdayMonday(modifiers) => {
293 parse_weekday_monday(input, *modifiers)
294 .and_then(|parsed| parsed.consume_value(|value| self.set_weekday(value)))
295 .ok_or(InvalidComponent("weekday"))
296 }
297 FormatDescriptionV3Inner::WeekNumberIso(modifiers) => {
298 parse_week_number_iso(input, *modifiers)
299 .and_then(|parsed| {
300 parsed.consume_value(|value| self.set_iso_week_number(NonZero::new(value)?))
301 })
302 .ok_or(InvalidComponent("week number"))
303 }
304 FormatDescriptionV3Inner::WeekNumberSunday(modifiers) => {
305 parse_week_number_sunday(input, *modifiers)
306 .and_then(|parsed| {
307 parsed.consume_value(|value| self.set_sunday_week_number(value))
308 })
309 .ok_or(InvalidComponent("week number"))
310 }
311 FormatDescriptionV3Inner::WeekNumberMonday(modifiers) => {
312 parse_week_number_monday(input, *modifiers)
313 .and_then(|parsed| {
314 parsed.consume_value(|value| self.set_monday_week_number(value))
315 })
316 .ok_or(InvalidComponent("week number"))
317 }
318 FormatDescriptionV3Inner::CalendarYearFullExtendedRange(modifiers) => {
319 parse_calendar_year_full_extended_range(input, *modifiers)
320 .and_then(|parsed| parsed.consume_value(|value| self.set_year(value)))
321 .ok_or(InvalidComponent("year"))
322 }
323 FormatDescriptionV3Inner::CalendarYearFullStandardRange(modifiers) => {
324 parse_calendar_year_full_standard_range(input, *modifiers)
325 .and_then(|parsed| parsed.consume_value(|value| self.set_year(value)))
326 .ok_or(InvalidComponent("year"))
327 }
328 FormatDescriptionV3Inner::IsoYearFullExtendedRange(modifiers) => {
329 parse_iso_year_full_extended_range(input, *modifiers)
330 .and_then(|parsed| parsed.consume_value(|value| self.set_iso_year(value)))
331 .ok_or(InvalidComponent("year"))
332 }
333 FormatDescriptionV3Inner::IsoYearFullStandardRange(modifiers) => {
334 parse_iso_year_full_standard_range(input, *modifiers)
335 .and_then(|parsed| parsed.consume_value(|value| self.set_iso_year(value)))
336 .ok_or(InvalidComponent("year"))
337 }
338 FormatDescriptionV3Inner::CalendarYearCenturyExtendedRange(modifiers) => {
339 parse_calendar_year_century_extended_range(input, *modifiers)
340 .and_then(|parsed| {
341 parsed.consume_value(|(value, is_negative)| {
342 self.set_year_century(value, is_negative)
343 })
344 })
345 .ok_or(InvalidComponent("year"))
346 }
347 FormatDescriptionV3Inner::CalendarYearCenturyStandardRange(modifiers) => {
348 parse_calendar_year_century_standard_range(input, *modifiers)
349 .and_then(|parsed| {
350 parsed.consume_value(|(value, is_negative)| {
351 self.set_year_century(value, is_negative)
352 })
353 })
354 .ok_or(InvalidComponent("year"))
355 }
356 FormatDescriptionV3Inner::IsoYearCenturyExtendedRange(modifiers) => {
357 parse_iso_year_century_extended_range(input, *modifiers)
358 .and_then(|parsed| {
359 parsed.consume_value(|(value, is_negative)| {
360 self.set_iso_year_century(value, is_negative)
361 })
362 })
363 .ok_or(InvalidComponent("year"))
364 }
365 FormatDescriptionV3Inner::IsoYearCenturyStandardRange(modifiers) => {
366 parse_iso_year_century_standard_range(input, *modifiers)
367 .and_then(|parsed| {
368 parsed.consume_value(|(value, is_negative)| {
369 self.set_iso_year_century(value, is_negative)
370 })
371 })
372 .ok_or(InvalidComponent("year"))
373 }
374 FormatDescriptionV3Inner::CalendarYearLastTwo(modifiers) => {
375 parse_calendar_year_last_two(input, *modifiers)
376 .and_then(|parsed| parsed.consume_value(|value| self.set_year_last_two(value)))
377 .ok_or(InvalidComponent("year"))
378 }
379 FormatDescriptionV3Inner::IsoYearLastTwo(modifiers) => {
380 parse_iso_year_last_two(input, *modifiers)
381 .and_then(|parsed| {
382 parsed.consume_value(|value| self.set_iso_year_last_two(value))
383 })
384 .ok_or(InvalidComponent("year"))
385 }
386 FormatDescriptionV3Inner::Hour12(modifiers) => parse_hour_12(input, *modifiers)
387 .and_then(|parsed| {
388 parsed.consume_value(|value| self.set_hour_12(NonZero::new(value)?))
389 })
390 .ok_or(InvalidComponent("hour")),
391 FormatDescriptionV3Inner::Hour24(modifiers) => parse_hour_24(input, *modifiers)
392 .and_then(|parsed| parsed.consume_value(|value| self.set_hour_24(value)))
393 .ok_or(InvalidComponent("hour")),
394 FormatDescriptionV3Inner::Minute(modifiers) => parse_minute(input, *modifiers)
395 .and_then(|parsed| parsed.consume_value(|value| self.set_minute(value)))
396 .ok_or(InvalidComponent("minute")),
397 FormatDescriptionV3Inner::Period(modifiers) => parse_period(input, *modifiers)
398 .and_then(|parsed| {
399 parsed.consume_value(|value| self.set_hour_12_is_pm(value == Period::Pm))
400 })
401 .ok_or(InvalidComponent("period")),
402 FormatDescriptionV3Inner::Second(modifiers) => parse_second(input, *modifiers)
403 .and_then(|parsed| parsed.consume_value(|value| self.set_second(value)))
404 .ok_or(InvalidComponent("second")),
405 FormatDescriptionV3Inner::Subsecond(modifiers) => parse_subsecond(input, *modifiers)
406 .and_then(|parsed| parsed.consume_value(|value| self.set_subsecond(value)))
407 .ok_or(InvalidComponent("subsecond")),
408 FormatDescriptionV3Inner::OffsetHour(modifiers) => parse_offset_hour(input, *modifiers)
409 .and_then(|parsed| {
410 parsed.consume_value(|(value, is_negative)| {
411 self.set_offset_hour(value)?;
412 self.offset_is_negative = is_negative;
413 Some(())
414 })
415 })
416 .ok_or(InvalidComponent("offset hour")),
417 FormatDescriptionV3Inner::OffsetMinute(modifiers) => {
418 parse_offset_minute(input, *modifiers)
419 .and_then(|parsed| {
420 parsed.consume_value(|value| self.set_offset_minute_signed(value))
421 })
422 .ok_or(InvalidComponent("offset minute"))
423 }
424 FormatDescriptionV3Inner::OffsetSecond(modifiers) => {
425 parse_offset_second(input, *modifiers)
426 .and_then(|parsed| {
427 parsed.consume_value(|value| self.set_offset_second_signed(value))
428 })
429 .ok_or(InvalidComponent("offset second"))
430 }
431 FormatDescriptionV3Inner::Ignore(modifiers) => {
432 let remaining = parse_ignore(input, *modifiers)
433 .map(ParsedItem::<()>::into_inner)
434 .ok_or(InvalidComponent("ignore"))?;
435
436 if remaining.is_empty() || remaining[0] & 0xC0 != 0x80 {
441 Ok(remaining)
442 } else {
443 Err(InvalidComponent("ignore"))
444 }
445 }
446 FormatDescriptionV3Inner::UnixTimestampSecond(modifiers) => {
447 parse_unix_timestamp_second(input, *modifiers)
448 .and_then(|parsed| {
449 parsed.consume_value(|value| self.set_unix_timestamp_nanos(value))
450 })
451 .ok_or(InvalidComponent("unix_timestamp"))
452 }
453 FormatDescriptionV3Inner::UnixTimestampMillisecond(modifiers) => {
454 parse_unix_timestamp_millisecond(input, *modifiers)
455 .and_then(|parsed| {
456 parsed.consume_value(|value| self.set_unix_timestamp_nanos(value))
457 })
458 .ok_or(InvalidComponent("unix_timestamp"))
459 }
460 FormatDescriptionV3Inner::UnixTimestampMicrosecond(modifiers) => {
461 parse_unix_timestamp_microsecond(input, *modifiers)
462 .and_then(|parsed| {
463 parsed.consume_value(|value| self.set_unix_timestamp_nanos(value))
464 })
465 .ok_or(InvalidComponent("unix_timestamp"))
466 }
467 FormatDescriptionV3Inner::UnixTimestampNanosecond(modifiers) => {
468 parse_unix_timestamp_nanosecond(input, *modifiers)
469 .and_then(|parsed| {
470 parsed.consume_value(|value| self.set_unix_timestamp_nanos(value))
471 })
472 .ok_or(InvalidComponent("unix_timestamp"))
473 }
474 FormatDescriptionV3Inner::End(modifiers) => parse_end(input, *modifiers)
475 .map(ParsedItem::<()>::into_inner)
476 .ok_or(error::ParseFromDescription::UnexpectedTrailingCharacters),
477 FormatDescriptionV3Inner::BorrowedLiteral(literal) => {
478 Self::parse_literal(input, literal.as_bytes())
479 }
480 FormatDescriptionV3Inner::BorrowedCompound(items) => {
481 let mut this = *self;
482 for item in *items {
483 input = this.parse_v3_inner(input, item)?;
484 }
485 *self = this;
486 Ok(input)
487 }
488 FormatDescriptionV3Inner::BorrowedOptional { format: _, item } => {
489 self.parse_v3_inner(input, item).or(Ok(input))
490 }
491 FormatDescriptionV3Inner::BorrowedFirst(items) => {
492 let mut first_err = None;
493
494 for item in items.iter() {
495 match self.parse_v3_inner(input, item) {
496 Ok(remaining_input) => return Ok(remaining_input),
497 Err(err) if first_err.is_none() => first_err = Some(err),
498 Err(_) => {}
499 }
500 }
501
502 match first_err {
503 Some(err) => Err(err),
504 None => Ok(input),
507 }
508 }
509 #[cfg(feature = "alloc")]
510 FormatDescriptionV3Inner::OwnedLiteral(literal) => {
511 Self::parse_literal(input, literal.as_bytes())
512 }
513 #[cfg(feature = "alloc")]
514 FormatDescriptionV3Inner::OwnedCompound(items) => {
515 let mut this = *self;
516 for item in items {
517 input = this.parse_v3_inner(input, item)?;
518 }
519 *self = this;
520 Ok(input)
521 }
522 #[cfg(feature = "alloc")]
523 FormatDescriptionV3Inner::OwnedOptional { format: _, item } => {
524 self.parse_v3_inner(input, item).or(Ok(input))
525 }
526 #[cfg(feature = "alloc")]
527 FormatDescriptionV3Inner::OwnedFirst(items) => {
528 let mut first_err = None;
529
530 for item in items {
531 match self.parse_v3_inner(input, item) {
532 Ok(remaining_input) => return Ok(remaining_input),
533 Err(err) if first_err.is_none() => first_err = Some(err),
534 Err(_) => {}
535 }
536 }
537
538 match first_err {
539 Some(err) => Err(err),
540 None => Ok(input),
543 }
544 }
545 }
546 }
547
548 #[inline]
554 pub fn parse_item<'a>(
555 &mut self,
556 input: &'a [u8],
557 item: &impl sealed::AnyFormatItem,
558 ) -> Result<&'a [u8], error::ParseFromDescription> {
559 item.parse_item(self, input)
560 }
561
562 #[inline]
568 pub fn parse_items<'a>(
569 &mut self,
570 mut input: &'a [u8],
571 items: &[impl sealed::AnyFormatItem],
572 ) -> Result<&'a [u8], error::ParseFromDescription> {
573 let mut this = *self;
576 for item in items {
577 input = this.parse_item(input, item)?;
578 }
579 *self = this;
580 Ok(input)
581 }
582
583 #[inline]
585 pub fn parse_literal<'a>(
586 input: &'a [u8],
587 literal: &[u8],
588 ) -> Result<&'a [u8], error::ParseFromDescription> {
589 input
590 .strip_prefix(literal)
591 .ok_or(error::ParseFromDescription::InvalidLiteral)
592 }
593
594 #[inline]
597 pub fn parse_component<'a>(
598 &mut self,
599 input: &'a [u8],
600 component: Component,
601 ) -> Result<&'a [u8], error::ParseFromDescription> {
602 use error::ParseFromDescription::InvalidComponent;
603
604 let v3_fd: FormatDescriptionV3Inner<'static> = component.into();
605
606 if let FormatDescriptionV3Inner::Ignore(modifiers) = v3_fd {
608 return parse_ignore(input, modifiers)
609 .map(ParsedItem::<()>::into_inner)
610 .ok_or(InvalidComponent("ignore"));
611 }
612
613 self.parse_v3_inner(input, &v3_fd)
615 }
616}
617
618impl Parsed {
620 #[inline]
622 pub const fn year(&self) -> Option<i32> {
623 self.year.get_primitive()
624 }
625
626 #[inline]
631 pub const fn year_century(&self) -> Option<i16> {
632 self.year_century.get_primitive()
633 }
634
635 #[inline]
640 pub const fn year_century_is_negative(&self) -> Option<bool> {
641 match self.year_century() {
642 Some(_) => Some(self.year_century_is_negative),
643 None => None,
644 }
645 }
646
647 #[inline]
649 pub const fn year_last_two(&self) -> Option<u8> {
650 self.year_last_two.get_primitive()
651 }
652
653 #[inline]
655 pub const fn iso_year(&self) -> Option<i32> {
656 self.iso_year.get_primitive()
657 }
658
659 #[inline]
664 pub const fn iso_year_century(&self) -> Option<i16> {
665 self.iso_year_century.get_primitive()
666 }
667
668 #[inline]
673 pub const fn iso_year_century_is_negative(&self) -> Option<bool> {
674 match self.iso_year_century() {
675 Some(_) => Some(self.iso_year_century_is_negative),
676 None => None,
677 }
678 }
679
680 #[inline]
682 pub const fn iso_year_last_two(&self) -> Option<u8> {
683 self.iso_year_last_two.get_primitive()
684 }
685
686 #[inline]
688 pub const fn month(&self) -> Option<Month> {
689 self.month
690 }
691
692 #[inline]
694 pub const fn sunday_week_number(&self) -> Option<u8> {
695 self.sunday_week_number.get_primitive()
696 }
697
698 #[inline]
700 pub const fn monday_week_number(&self) -> Option<u8> {
701 self.monday_week_number.get_primitive()
702 }
703
704 #[inline]
706 pub const fn iso_week_number(&self) -> Option<NonZero<u8>> {
707 NonZero::new(const_try_opt!(self.iso_week_number.get_primitive()))
708 }
709
710 #[inline]
712 pub const fn weekday(&self) -> Option<Weekday> {
713 self.weekday
714 }
715
716 #[inline]
718 pub const fn ordinal(&self) -> Option<NonZero<u16>> {
719 NonZero::new(const_try_opt!(self.ordinal.get_primitive()))
720 }
721
722 #[inline]
724 pub const fn day(&self) -> Option<NonZero<u8>> {
725 NonZero::new(const_try_opt!(self.day.get_primitive()))
726 }
727
728 #[inline]
730 pub const fn hour_24(&self) -> Option<u8> {
731 self.hour_24.get_primitive()
732 }
733
734 #[inline]
736 pub const fn hour_12(&self) -> Option<NonZero<u8>> {
737 NonZero::new(const_try_opt!(self.hour_12.get_primitive()))
738 }
739
740 #[inline]
742 pub const fn hour_12_is_pm(&self) -> Option<bool> {
743 self.hour_12_is_pm
744 }
745
746 #[inline]
748 pub const fn minute(&self) -> Option<u8> {
749 self.minute.get_primitive()
750 }
751
752 #[inline]
754 pub const fn second(&self) -> Option<u8> {
755 self.second.get_primitive()
756 }
757
758 #[inline]
760 pub const fn subsecond(&self) -> Option<u32> {
761 self.subsecond.get_primitive()
762 }
763
764 #[inline]
766 pub const fn offset_hour(&self) -> Option<i8> {
767 self.offset_hour.get_primitive()
768 }
769
770 #[doc(hidden)]
772 #[deprecated(since = "0.3.8", note = "use `parsed.offset_minute_signed()` instead")]
773 #[inline]
774 pub const fn offset_minute(&self) -> Option<u8> {
775 Some(const_try_opt!(self.offset_minute_signed()).unsigned_abs())
776 }
777
778 #[inline]
780 pub const fn offset_minute_signed(&self) -> Option<i8> {
781 match (self.offset_minute.get_primitive(), self.offset_is_negative) {
782 (Some(offset_minute), true) => Some(-offset_minute),
783 (Some(offset_minute), _) => Some(offset_minute),
784 (None, _) => None,
785 }
786 }
787
788 #[doc(hidden)]
790 #[deprecated(since = "0.3.8", note = "use `parsed.offset_second_signed()` instead")]
791 #[inline]
792 pub const fn offset_second(&self) -> Option<u8> {
793 Some(const_try_opt!(self.offset_second_signed()).unsigned_abs())
794 }
795
796 #[inline]
798 pub const fn offset_second_signed(&self) -> Option<i8> {
799 match (self.offset_second.get_primitive(), self.offset_is_negative) {
800 (Some(offset_second), true) => Some(-offset_second),
801 (Some(offset_second), _) => Some(offset_second),
802 (None, _) => None,
803 }
804 }
805
806 #[inline]
808 pub const fn unix_timestamp_nanos(&self) -> Option<i128> {
809 self.unix_timestamp_nanos.get_primitive()
810 }
811}
812
813macro_rules! setters {
815 ($($name:ident $setter:ident $builder:ident $type:ty;)*) => {$(
816 #[doc = concat!("Set the `", stringify!($name), "` component.")]
817 #[inline]
818 pub const fn $setter(&mut self, value: $type) -> Option<()> {
819 match self.$builder(value) {
820 Some(value) => {
821 *self = value;
822 Some(())
823 },
824 None => None,
825 }
826 }
827 )*};
828}
829
830impl Parsed {
835 setters! {
836 year set_year with_year i32;
837 }
838
839 #[inline]
844 pub const fn set_year_century(&mut self, value: i16, is_negative: bool) -> Option<()> {
845 self.year_century = Option_ri16::Some(const_try_opt!(ri16::new(value)));
846 if value != 0 {
847 self.year_century_is_negative = value.is_negative();
848 } else {
849 self.year_century_is_negative = is_negative;
850 }
851 Some(())
852 }
853
854 setters! {
855 year_last_two set_year_last_two with_year_last_two u8;
856 iso_year set_iso_year with_iso_year i32;
857 iso_year_last_two set_iso_year_last_two with_iso_year_last_two u8;
858 }
859
860 #[inline]
865 pub const fn set_iso_year_century(&mut self, value: i16, is_negative: bool) -> Option<()> {
866 self.iso_year_century = Option_ri16::Some(const_try_opt!(ri16::new(value)));
867 if value != 0 {
868 self.iso_year_century_is_negative = value.is_negative();
869 } else {
870 self.iso_year_century_is_negative = is_negative;
871 }
872 Some(())
873 }
874
875 setters! {
876 month set_month with_month Month;
877 sunday_week_number set_sunday_week_number with_sunday_week_number u8;
878 monday_week_number set_monday_week_number with_monday_week_number u8;
879 iso_week_number set_iso_week_number with_iso_week_number NonZero<u8>;
880 weekday set_weekday with_weekday Weekday;
881 ordinal set_ordinal with_ordinal NonZero<u16>;
882 day set_day with_day NonZero<u8>;
883 hour_24 set_hour_24 with_hour_24 u8;
884 hour_12 set_hour_12 with_hour_12 NonZero<u8>;
885 hour_12_is_pm set_hour_12_is_pm with_hour_12_is_pm bool;
886 minute set_minute with_minute u8;
887 second set_second with_second u8;
888 subsecond set_subsecond with_subsecond u32;
889 offset_hour set_offset_hour with_offset_hour i8;
890 offset_minute set_offset_minute_signed with_offset_minute_signed i8;
891 offset_second set_offset_second_signed with_offset_second_signed i8;
892 unix_timestamp_nanos set_unix_timestamp_nanos with_unix_timestamp_nanos i128;
893 }
894
895 #[doc(hidden)]
897 #[deprecated(
898 since = "0.3.8",
899 note = "use `parsed.set_offset_minute_signed()` instead"
900 )]
901 #[inline]
902 pub const fn set_offset_minute(&mut self, value: u8) -> Option<()> {
903 if value > i8::MAX.cast_unsigned() {
904 None
905 } else {
906 self.set_offset_minute_signed(value.cast_signed())
907 }
908 }
909
910 #[doc(hidden)]
912 #[deprecated(
913 since = "0.3.8",
914 note = "use `parsed.set_offset_second_signed()` instead"
915 )]
916 #[inline]
917 pub const fn set_offset_second(&mut self, value: u8) -> Option<()> {
918 if value > i8::MAX.cast_unsigned() {
919 None
920 } else {
921 self.set_offset_second_signed(value.cast_signed())
922 }
923 }
924}
925
926impl Parsed {
931 #[inline]
933 pub const fn with_year(mut self, value: i32) -> Option<Self> {
934 self.year = Option_ri32::Some(const_try_opt!(ri32::new(value)));
935 Some(self)
936 }
937
938 #[inline]
943 pub const fn with_year_century(mut self, value: i16, is_negative: bool) -> Option<Self> {
944 self.year_century = Option_ri16::Some(const_try_opt!(ri16::new(value)));
945 if value != 0 {
946 self.year_century_is_negative = value.is_negative();
947 } else {
948 self.year_century_is_negative = is_negative;
949 }
950 Some(self)
951 }
952
953 #[inline]
955 pub const fn with_year_last_two(mut self, value: u8) -> Option<Self> {
956 self.year_last_two = Option_ru8::Some(const_try_opt!(ru8::new(value)));
957 Some(self)
958 }
959
960 #[inline]
962 pub const fn with_iso_year(mut self, value: i32) -> Option<Self> {
963 self.iso_year = Option_ri32::Some(const_try_opt!(ri32::new(value)));
964 Some(self)
965 }
966
967 #[inline]
972 pub const fn with_iso_year_century(mut self, value: i16, is_negative: bool) -> Option<Self> {
973 self.iso_year_century = Option_ri16::Some(const_try_opt!(ri16::new(value)));
974 if value != 0 {
975 self.iso_year_century_is_negative = value.is_negative();
976 } else {
977 self.iso_year_century_is_negative = is_negative;
978 }
979 Some(self)
980 }
981
982 #[inline]
984 pub const fn with_iso_year_last_two(mut self, value: u8) -> Option<Self> {
985 self.iso_year_last_two = Option_ru8::Some(const_try_opt!(ru8::new(value)));
986 Some(self)
987 }
988
989 #[inline]
991 pub const fn with_month(mut self, value: Month) -> Option<Self> {
992 self.month = Some(value);
993 Some(self)
994 }
995
996 #[inline]
998 pub const fn with_sunday_week_number(mut self, value: u8) -> Option<Self> {
999 self.sunday_week_number = Option_ru8::Some(const_try_opt!(ru8::new(value)));
1000 Some(self)
1001 }
1002
1003 #[inline]
1005 pub const fn with_monday_week_number(mut self, value: u8) -> Option<Self> {
1006 self.monday_week_number = Option_ru8::Some(const_try_opt!(ru8::new(value)));
1007 Some(self)
1008 }
1009
1010 #[inline]
1012 pub const fn with_iso_week_number(mut self, value: NonZero<u8>) -> Option<Self> {
1013 self.iso_week_number = Option_ru8::Some(const_try_opt!(ru8::new(value.get())));
1014 Some(self)
1015 }
1016
1017 #[inline]
1019 pub const fn with_weekday(mut self, value: Weekday) -> Option<Self> {
1020 self.weekday = Some(value);
1021 Some(self)
1022 }
1023
1024 #[inline]
1026 pub const fn with_ordinal(mut self, value: NonZero<u16>) -> Option<Self> {
1027 self.ordinal = Option_ru16::Some(const_try_opt!(ru16::new(value.get())));
1028 Some(self)
1029 }
1030
1031 #[inline]
1033 pub const fn with_day(mut self, value: NonZero<u8>) -> Option<Self> {
1034 self.day = Option_ru8::Some(const_try_opt!(ru8::new(value.get())));
1035 Some(self)
1036 }
1037
1038 #[inline]
1040 pub const fn with_hour_24(mut self, value: u8) -> Option<Self> {
1041 self.hour_24 = Option_ru8::Some(const_try_opt!(ru8::new(value)));
1042 Some(self)
1043 }
1044
1045 #[inline]
1047 pub const fn with_hour_12(mut self, value: NonZero<u8>) -> Option<Self> {
1048 self.hour_12 = Option_ru8::Some(const_try_opt!(ru8::new(value.get())));
1049 Some(self)
1050 }
1051
1052 #[inline]
1054 pub const fn with_hour_12_is_pm(mut self, value: bool) -> Option<Self> {
1055 self.hour_12_is_pm = Some(value);
1056 Some(self)
1057 }
1058
1059 #[inline]
1061 pub const fn with_minute(mut self, value: u8) -> Option<Self> {
1062 self.minute = Option_ru8::Some(const_try_opt!(ru8::new(value)));
1063 Some(self)
1064 }
1065
1066 #[inline]
1068 pub const fn with_second(mut self, value: u8) -> Option<Self> {
1069 self.second = Option_ru8::Some(const_try_opt!(ru8::new(value)));
1070 Some(self)
1071 }
1072
1073 #[inline]
1075 pub const fn with_subsecond(mut self, value: u32) -> Option<Self> {
1076 self.subsecond = Option_ru32::Some(const_try_opt!(ru32::new(value)));
1077 Some(self)
1078 }
1079
1080 #[inline]
1082 pub const fn with_offset_hour(mut self, value: i8) -> Option<Self> {
1083 self.offset_hour = Option_ri8::Some(const_try_opt!(ri8::new(value)));
1084 Some(self)
1085 }
1086
1087 #[doc(hidden)]
1089 #[deprecated(
1090 since = "0.3.8",
1091 note = "use `parsed.with_offset_minute_signed()` instead"
1092 )]
1093 #[inline]
1094 pub const fn with_offset_minute(self, value: u8) -> Option<Self> {
1095 if value > i8::MAX.cast_unsigned() {
1096 None
1097 } else {
1098 self.with_offset_minute_signed(value.cast_signed())
1099 }
1100 }
1101
1102 #[inline]
1104 pub const fn with_offset_minute_signed(mut self, value: i8) -> Option<Self> {
1105 self.offset_minute = Option_ri8::Some(const_try_opt!(ri8::new(value)));
1106 Some(self)
1107 }
1108
1109 #[doc(hidden)]
1111 #[deprecated(
1112 since = "0.3.8",
1113 note = "use `parsed.with_offset_second_signed()` instead"
1114 )]
1115 #[inline]
1116 pub const fn with_offset_second(self, value: u8) -> Option<Self> {
1117 if value > i8::MAX.cast_unsigned() {
1118 None
1119 } else {
1120 self.with_offset_second_signed(value.cast_signed())
1121 }
1122 }
1123
1124 #[inline]
1126 pub const fn with_offset_second_signed(mut self, value: i8) -> Option<Self> {
1127 self.offset_second = Option_ri8::Some(const_try_opt!(ri8::new(value)));
1128 Some(self)
1129 }
1130
1131 #[inline]
1133 pub const fn with_unix_timestamp_nanos(mut self, value: i128) -> Option<Self> {
1134 self.unix_timestamp_nanos = Option_ri128::Some(const_try_opt!(ri128::new(value)));
1135 Some(self)
1136 }
1137}
1138
1139impl TryFrom<Parsed> for Date {
1140 type Error = error::TryFromParsed;
1141
1142 #[inline]
1143 fn try_from(mut parsed: Parsed) -> Result<Self, Self::Error> {
1144 macro_rules! match_ {
1146 (_ => $catch_all:expr $(,)?) => {
1147 $catch_all
1148 };
1149 (($($name:ident),* $(,)?) => $arm:expr, $($rest:tt)*) => {
1150 if let ($(Some($name)),*) = ($(parsed.$name()),*) {
1151 $arm
1152 } else {
1153 match_!($($rest)*)
1154 }
1155 };
1156 }
1157
1158 #[inline]
1161 const fn adjustment(year: i32) -> i16 {
1162 match unsafe { Date::__from_ordinal_date_unchecked(year, 1) }.weekday() {
1164 Weekday::Monday => 7,
1165 Weekday::Tuesday => 1,
1166 Weekday::Wednesday => 2,
1167 Weekday::Thursday => 3,
1168 Weekday::Friday => 4,
1169 Weekday::Saturday => 5,
1170 Weekday::Sunday => 6,
1171 }
1172 }
1173
1174 if let (None, Some(century), Some(is_negative), Some(last_two)) = (
1177 parsed.year(),
1178 parsed.year_century(),
1179 parsed.year_century_is_negative(),
1180 parsed.year_last_two(),
1181 ) {
1182 let year = if is_negative {
1183 100 * century.widen::<i32>() - last_two.cast_signed().widen::<i32>()
1184 } else {
1185 100 * century.widen::<i32>() + last_two.cast_signed().widen::<i32>()
1186 };
1187 parsed.year = Option_ri32::from(ri32::new(year));
1188 }
1189 if let (None, Some(century), Some(is_negative), Some(last_two)) = (
1190 parsed.iso_year(),
1191 parsed.iso_year_century(),
1192 parsed.iso_year_century_is_negative(),
1193 parsed.iso_year_last_two(),
1194 ) {
1195 let iso_year = if is_negative {
1196 100 * century.widen::<i32>() - last_two.cast_signed().widen::<i32>()
1197 } else {
1198 100 * century.widen::<i32>() + last_two.cast_signed().widen::<i32>()
1199 };
1200 parsed.iso_year = Option_ri32::from(ri32::new(iso_year));
1201 }
1202
1203 match_! {
1204 (year, ordinal) => Ok(Self::from_ordinal_date(year, ordinal.get())?),
1205 (year, month, day) => Ok(Self::from_calendar_date(year, month, day.get())?),
1206 (iso_year, iso_week_number, weekday) => Ok(Self::from_iso_week_date(
1207 iso_year,
1208 iso_week_number.get(),
1209 weekday,
1210 )?),
1211 (year, sunday_week_number, weekday) => Ok(Self::from_ordinal_date(
1212 year,
1213 (sunday_week_number.cast_signed().widen::<i16>() * 7
1214 + weekday.number_days_from_sunday().cast_signed().widen::<i16>()
1215 - adjustment(year)
1216 + 1).cast_unsigned(),
1217 )?),
1218 (year, monday_week_number, weekday) => Ok(Self::from_ordinal_date(
1219 year,
1220 (monday_week_number.cast_signed().widen::<i16>() * 7
1221 + weekday.number_days_from_monday().cast_signed().widen::<i16>()
1222 - adjustment(year)
1223 + 1).cast_unsigned(),
1224 )?),
1225 _ => Err(InsufficientInformation),
1226 }
1227 }
1228}
1229
1230impl TryFrom<Parsed> for Time {
1231 type Error = error::TryFromParsed;
1232
1233 #[inline]
1234 fn try_from(parsed: Parsed) -> Result<Self, Self::Error> {
1235 let hour = match (parsed.hour_24(), parsed.hour_12(), parsed.hour_12_is_pm()) {
1236 (Some(hour), _, _) => hour,
1237 (_, Some(hour), Some(false)) if hour.get() == 12 => 0,
1238 (_, Some(hour), Some(true)) if hour.get() == 12 => 12,
1239 (_, Some(hour), Some(false)) => hour.get(),
1240 (_, Some(hour), Some(true)) => hour.get() + 12,
1241 _ => return Err(InsufficientInformation),
1242 };
1243
1244 if parsed.hour_24().is_none()
1245 && parsed.hour_12().is_some()
1246 && parsed.hour_12_is_pm().is_some()
1247 && parsed.minute().is_none()
1248 && parsed.second().is_none()
1249 && parsed.subsecond().is_none()
1250 {
1251 return Ok(Self::from_hms_nano(hour, 0, 0, 0)?);
1252 }
1253
1254 match (parsed.minute(), parsed.second(), parsed.subsecond()) {
1256 (None, None, None) => Ok(Self::from_hms_nano(hour, 0, 0, 0)?),
1257 (Some(minute), None, None) => Ok(Self::from_hms_nano(hour, minute, 0, 0)?),
1258 (Some(minute), Some(second), None) => Ok(Self::from_hms_nano(hour, minute, second, 0)?),
1259 (Some(minute), Some(second), Some(subsecond)) => {
1260 Ok(Self::from_hms_nano(hour, minute, second, subsecond)?)
1261 }
1262 _ => Err(InsufficientInformation),
1263 }
1264 }
1265}
1266
1267#[inline]
1268fn utc_offset_try_from_parsed<const REQUIRED: bool>(
1269 parsed: Parsed,
1270) -> Result<UtcOffset, error::TryFromParsed> {
1271 let hour = match (REQUIRED, parsed.offset_hour()) {
1272 (true, None) => return Err(InsufficientInformation),
1274 (false, None) => return Ok(UtcOffset::UTC),
1277 (_, Some(hour)) => hour,
1279 };
1280 let minute = parsed.offset_minute_signed();
1281 let second = minute.and_then(|_| parsed.offset_second_signed());
1283
1284 let minute = minute.unwrap_or(0);
1285 let second = second.unwrap_or(0);
1286
1287 UtcOffset::from_hms(hour, minute, second).map_err(Into::into)
1288}
1289
1290impl TryFrom<Parsed> for UtcOffset {
1291 type Error = error::TryFromParsed;
1292
1293 #[inline]
1294 fn try_from(parsed: Parsed) -> Result<Self, Self::Error> {
1295 utc_offset_try_from_parsed::<true>(parsed)
1296 }
1297}
1298
1299impl TryFrom<Parsed> for PrimitiveDateTime {
1300 type Error = error::TryFromParsed;
1301
1302 #[inline]
1303 fn try_from(parsed: Parsed) -> Result<Self, Self::Error> {
1304 Ok(Self::new(parsed.try_into()?, parsed.try_into()?))
1305 }
1306}
1307
1308impl TryFrom<Parsed> for UtcDateTime {
1309 type Error = error::TryFromParsed;
1310
1311 #[inline]
1312 fn try_from(mut parsed: Parsed) -> Result<Self, Self::Error> {
1313 if let Some(timestamp) = parsed.unix_timestamp_nanos() {
1314 let mut value = Self::from_unix_timestamp_nanos(timestamp)?;
1315 if let Some(subsecond) = parsed.subsecond() {
1316 value = value.replace_nanosecond(subsecond)?;
1317 }
1318 return Ok(value);
1319 }
1320
1321 let leap_second_input = if parsed.leap_second_allowed && parsed.second() == Some(60) {
1325 if parsed.set_second(59).is_none() {
1326 bug!("59 is a valid second");
1327 }
1328 if parsed.set_subsecond(999_999_999).is_none() {
1329 bug!("999_999_999 is a valid subsecond");
1330 }
1331 true
1332 } else {
1333 false
1334 };
1335
1336 let dt = OffsetDateTime::new_in_offset(
1337 Date::try_from(parsed)?,
1338 Time::try_from(parsed)?,
1339 utc_offset_try_from_parsed::<false>(parsed)?,
1340 )
1341 .to_utc();
1342
1343 if leap_second_input && !dt.is_valid_leap_second_stand_in() {
1344 return Err(error::TryFromParsed::ComponentRange(
1345 error::ComponentRange::conditional("second"),
1346 ));
1347 }
1348 Ok(dt)
1349 }
1350}
1351
1352impl TryFrom<Parsed> for OffsetDateTime {
1353 type Error = error::TryFromParsed;
1354
1355 #[inline]
1356 fn try_from(mut parsed: Parsed) -> Result<Self, Self::Error> {
1357 if let Some(timestamp) = parsed.unix_timestamp_nanos() {
1358 let mut value = Self::from_unix_timestamp_nanos(timestamp)?;
1359 if let Some(subsecond) = parsed.subsecond() {
1360 value = value.replace_nanosecond(subsecond)?;
1361 }
1362 return Ok(value);
1363 }
1364
1365 let leap_second_input = if parsed.leap_second_allowed && parsed.second() == Some(60) {
1369 if parsed.set_second(59).is_none() {
1370 bug!("59 is a valid second");
1371 }
1372 if parsed.set_subsecond(999_999_999).is_none() {
1373 bug!("999_999_999 is a valid subsecond");
1374 }
1375 true
1376 } else {
1377 false
1378 };
1379
1380 let dt = Self::new_in_offset(
1381 Date::try_from(parsed)?,
1382 Time::try_from(parsed)?,
1383 UtcOffset::try_from(parsed)?,
1384 );
1385
1386 if leap_second_input && !dt.is_valid_leap_second_stand_in() {
1387 return Err(error::TryFromParsed::ComponentRange(
1388 error::ComponentRange::conditional("second"),
1389 ));
1390 }
1391 Ok(dt)
1392 }
1393}
1394
1395impl TryFrom<Parsed> for Timestamp {
1396 type Error = error::TryFromParsed;
1397
1398 #[inline]
1399 fn try_from(parsed: Parsed) -> Result<Self, Self::Error> {
1400 if let Some(timestamp) = parsed.unix_timestamp_nanos() {
1402 return Ok(Self::from_nanoseconds(timestamp)?);
1403 }
1404 if let Ok(dt) = UtcDateTime::try_from(parsed) {
1406 return Ok(dt.into());
1407 }
1408 Err(InsufficientInformation)
1409 }
1410}