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, 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 use error::ParseFromDescription::InvalidComponent;
257
258 match format_description {
259 FormatDescriptionV3Inner::Day(modifiers) => parse_day(input, *modifiers)
260 .and_then(|parsed| parsed.consume_value(|value| self.set_day(value)))
261 .ok_or(InvalidComponent("day")),
262 FormatDescriptionV3Inner::MonthShort(modifiers) => parse_month_short(input, *modifiers)
263 .and_then(|parsed| parsed.consume_value(|value| self.set_month(value)))
264 .ok_or(InvalidComponent("month")),
265 FormatDescriptionV3Inner::MonthLong(modifiers) => parse_month_long(input, *modifiers)
266 .and_then(|parsed| parsed.consume_value(|value| self.set_month(value)))
267 .ok_or(InvalidComponent("month")),
268 FormatDescriptionV3Inner::MonthNumerical(modifiers) => {
269 parse_month_numerical(input, *modifiers)
270 .and_then(|parsed| parsed.consume_value(|value| self.set_month(value)))
271 .ok_or(InvalidComponent("month"))
272 }
273 FormatDescriptionV3Inner::Ordinal(modifiers) => parse_ordinal(input, *modifiers)
274 .and_then(|parsed| parsed.consume_value(|value| self.set_ordinal(value)))
275 .ok_or(InvalidComponent("ordinal")),
276 FormatDescriptionV3Inner::WeekdayShort(modifiers) => {
277 parse_weekday_short(input, *modifiers)
278 .and_then(|parsed| parsed.consume_value(|value| self.set_weekday(value)))
279 .ok_or(InvalidComponent("weekday"))
280 }
281 FormatDescriptionV3Inner::WeekdayLong(modifiers) => {
282 parse_weekday_long(input, *modifiers)
283 .and_then(|parsed| parsed.consume_value(|value| self.set_weekday(value)))
284 .ok_or(InvalidComponent("weekday"))
285 }
286 FormatDescriptionV3Inner::WeekdaySunday(modifiers) => {
287 parse_weekday_sunday(input, *modifiers)
288 .and_then(|parsed| parsed.consume_value(|value| self.set_weekday(value)))
289 .ok_or(InvalidComponent("weekday"))
290 }
291 FormatDescriptionV3Inner::WeekdayMonday(modifiers) => {
292 parse_weekday_monday(input, *modifiers)
293 .and_then(|parsed| parsed.consume_value(|value| self.set_weekday(value)))
294 .ok_or(InvalidComponent("weekday"))
295 }
296 FormatDescriptionV3Inner::WeekNumberIso(modifiers) => {
297 parse_week_number_iso(input, *modifiers)
298 .and_then(|parsed| {
299 parsed.consume_value(|value| self.set_iso_week_number(NonZero::new(value)?))
300 })
301 .ok_or(InvalidComponent("week number"))
302 }
303 FormatDescriptionV3Inner::WeekNumberSunday(modifiers) => {
304 parse_week_number_sunday(input, *modifiers)
305 .and_then(|parsed| {
306 parsed.consume_value(|value| self.set_sunday_week_number(value))
307 })
308 .ok_or(InvalidComponent("week number"))
309 }
310 FormatDescriptionV3Inner::WeekNumberMonday(modifiers) => {
311 parse_week_number_monday(input, *modifiers)
312 .and_then(|parsed| {
313 parsed.consume_value(|value| self.set_monday_week_number(value))
314 })
315 .ok_or(InvalidComponent("week number"))
316 }
317 FormatDescriptionV3Inner::CalendarYearFullExtendedRange(modifiers) => {
318 parse_calendar_year_full_extended_range(input, *modifiers)
319 .and_then(|parsed| parsed.consume_value(|value| self.set_year(value)))
320 .ok_or(InvalidComponent("year"))
321 }
322 FormatDescriptionV3Inner::CalendarYearFullStandardRange(modifiers) => {
323 parse_calendar_year_full_standard_range(input, *modifiers)
324 .and_then(|parsed| parsed.consume_value(|value| self.set_year(value)))
325 .ok_or(InvalidComponent("year"))
326 }
327 FormatDescriptionV3Inner::IsoYearFullExtendedRange(modifiers) => {
328 parse_iso_year_full_extended_range(input, *modifiers)
329 .and_then(|parsed| parsed.consume_value(|value| self.set_iso_year(value)))
330 .ok_or(InvalidComponent("year"))
331 }
332 FormatDescriptionV3Inner::IsoYearFullStandardRange(modifiers) => {
333 parse_iso_year_full_standard_range(input, *modifiers)
334 .and_then(|parsed| parsed.consume_value(|value| self.set_iso_year(value)))
335 .ok_or(InvalidComponent("year"))
336 }
337 FormatDescriptionV3Inner::CalendarYearCenturyExtendedRange(modifiers) => {
338 parse_calendar_year_century_extended_range(input, *modifiers)
339 .and_then(|parsed| {
340 parsed.consume_value(|(value, is_negative)| {
341 self.set_year_century(value, is_negative)
342 })
343 })
344 .ok_or(InvalidComponent("year"))
345 }
346 FormatDescriptionV3Inner::CalendarYearCenturyStandardRange(modifiers) => {
347 parse_calendar_year_century_standard_range(input, *modifiers)
348 .and_then(|parsed| {
349 parsed.consume_value(|(value, is_negative)| {
350 self.set_year_century(value, is_negative)
351 })
352 })
353 .ok_or(InvalidComponent("year"))
354 }
355 FormatDescriptionV3Inner::IsoYearCenturyExtendedRange(modifiers) => {
356 parse_iso_year_century_extended_range(input, *modifiers)
357 .and_then(|parsed| {
358 parsed.consume_value(|(value, is_negative)| {
359 self.set_iso_year_century(value, is_negative)
360 })
361 })
362 .ok_or(InvalidComponent("year"))
363 }
364 FormatDescriptionV3Inner::IsoYearCenturyStandardRange(modifiers) => {
365 parse_iso_year_century_standard_range(input, *modifiers)
366 .and_then(|parsed| {
367 parsed.consume_value(|(value, is_negative)| {
368 self.set_iso_year_century(value, is_negative)
369 })
370 })
371 .ok_or(InvalidComponent("year"))
372 }
373 FormatDescriptionV3Inner::CalendarYearLastTwo(modifiers) => {
374 parse_calendar_year_last_two(input, *modifiers)
375 .and_then(|parsed| parsed.consume_value(|value| self.set_year_last_two(value)))
376 .ok_or(InvalidComponent("year"))
377 }
378 FormatDescriptionV3Inner::IsoYearLastTwo(modifiers) => {
379 parse_iso_year_last_two(input, *modifiers)
380 .and_then(|parsed| {
381 parsed.consume_value(|value| self.set_iso_year_last_two(value))
382 })
383 .ok_or(InvalidComponent("year"))
384 }
385 FormatDescriptionV3Inner::Hour12(modifiers) => parse_hour_12(input, *modifiers)
386 .and_then(|parsed| {
387 parsed.consume_value(|value| self.set_hour_12(NonZero::new(value)?))
388 })
389 .ok_or(InvalidComponent("hour")),
390 FormatDescriptionV3Inner::Hour24(modifiers) => parse_hour_24(input, *modifiers)
391 .and_then(|parsed| parsed.consume_value(|value| self.set_hour_24(value)))
392 .ok_or(InvalidComponent("hour")),
393 FormatDescriptionV3Inner::Minute(modifiers) => parse_minute(input, *modifiers)
394 .and_then(|parsed| parsed.consume_value(|value| self.set_minute(value)))
395 .ok_or(InvalidComponent("minute")),
396 FormatDescriptionV3Inner::Period(modifiers) => parse_period(input, *modifiers)
397 .and_then(|parsed| {
398 parsed.consume_value(|value| self.set_hour_12_is_pm(value == Period::Pm))
399 })
400 .ok_or(InvalidComponent("period")),
401 FormatDescriptionV3Inner::Second(modifiers) => parse_second(input, *modifiers)
402 .and_then(|parsed| parsed.consume_value(|value| self.set_second(value)))
403 .ok_or(InvalidComponent("second")),
404 FormatDescriptionV3Inner::Subsecond(modifiers) => parse_subsecond(input, *modifiers)
405 .and_then(|parsed| parsed.consume_value(|value| self.set_subsecond(value)))
406 .ok_or(InvalidComponent("subsecond")),
407 FormatDescriptionV3Inner::OffsetHour(modifiers) => parse_offset_hour(input, *modifiers)
408 .and_then(|parsed| {
409 parsed.consume_value(|(value, is_negative)| {
410 self.set_offset_hour(value)?;
411 self.offset_is_negative = is_negative;
412 Some(())
413 })
414 })
415 .ok_or(InvalidComponent("offset hour")),
416 FormatDescriptionV3Inner::OffsetMinute(modifiers) => {
417 parse_offset_minute(input, *modifiers)
418 .and_then(|parsed| {
419 parsed.consume_value(|value| self.set_offset_minute_signed(value))
420 })
421 .ok_or(InvalidComponent("offset minute"))
422 }
423 FormatDescriptionV3Inner::OffsetSecond(modifiers) => {
424 parse_offset_second(input, *modifiers)
425 .and_then(|parsed| {
426 parsed.consume_value(|value| self.set_offset_second_signed(value))
427 })
428 .ok_or(InvalidComponent("offset second"))
429 }
430 FormatDescriptionV3Inner::Ignore(modifiers) => {
431 let remaining = parse_ignore(input, *modifiers)
432 .map(ParsedItem::<()>::into_inner)
433 .ok_or(InvalidComponent("ignore"))?;
434
435 if remaining.is_empty() || remaining[0] & 0xC0 != 0x80 {
440 Ok(remaining)
441 } else {
442 Err(InvalidComponent("ignore"))
443 }
444 }
445 FormatDescriptionV3Inner::UnixTimestampSecond(modifiers) => {
446 parse_unix_timestamp_second(input, *modifiers)
447 .and_then(|parsed| {
448 parsed.consume_value(|value| self.set_unix_timestamp_nanos(value))
449 })
450 .ok_or(InvalidComponent("unix_timestamp"))
451 }
452 FormatDescriptionV3Inner::UnixTimestampMillisecond(modifiers) => {
453 parse_unix_timestamp_millisecond(input, *modifiers)
454 .and_then(|parsed| {
455 parsed.consume_value(|value| self.set_unix_timestamp_nanos(value))
456 })
457 .ok_or(InvalidComponent("unix_timestamp"))
458 }
459 FormatDescriptionV3Inner::UnixTimestampMicrosecond(modifiers) => {
460 parse_unix_timestamp_microsecond(input, *modifiers)
461 .and_then(|parsed| {
462 parsed.consume_value(|value| self.set_unix_timestamp_nanos(value))
463 })
464 .ok_or(InvalidComponent("unix_timestamp"))
465 }
466 FormatDescriptionV3Inner::UnixTimestampNanosecond(modifiers) => {
467 parse_unix_timestamp_nanosecond(input, *modifiers)
468 .and_then(|parsed| {
469 parsed.consume_value(|value| self.set_unix_timestamp_nanos(value))
470 })
471 .ok_or(InvalidComponent("unix_timestamp"))
472 }
473 FormatDescriptionV3Inner::End(modifiers) => parse_end(input, *modifiers)
474 .map(ParsedItem::<()>::into_inner)
475 .ok_or(error::ParseFromDescription::UnexpectedTrailingCharacters),
476 FormatDescriptionV3Inner::BorrowedLiteral(literal) => {
477 Self::parse_literal(input, literal.as_bytes())
478 }
479 FormatDescriptionV3Inner::BorrowedCompound(items) => {
480 let mut this = *self;
481 for item in *items {
482 input = this.parse_v3_inner(input, item)?;
483 }
484 *self = this;
485 Ok(input)
486 }
487 FormatDescriptionV3Inner::BorrowedOptional { format: _, item } => {
488 self.parse_v3_inner(input, item).or(Ok(input))
489 }
490 FormatDescriptionV3Inner::BorrowedFirst(items) => {
491 let mut first_err = None;
492
493 for item in items.iter() {
494 match self.parse_v3_inner(input, item) {
495 Ok(remaining_input) => return Ok(remaining_input),
496 Err(err) if first_err.is_none() => first_err = Some(err),
497 Err(_) => {}
498 }
499 }
500
501 match first_err {
502 Some(err) => Err(err),
503 None => Ok(input),
506 }
507 }
508 #[cfg(feature = "alloc")]
509 FormatDescriptionV3Inner::OwnedLiteral(literal) => {
510 Self::parse_literal(input, literal.as_bytes())
511 }
512 #[cfg(feature = "alloc")]
513 FormatDescriptionV3Inner::OwnedCompound(items) => {
514 let mut this = *self;
515 for item in items {
516 input = this.parse_v3_inner(input, item)?;
517 }
518 *self = this;
519 Ok(input)
520 }
521 #[cfg(feature = "alloc")]
522 FormatDescriptionV3Inner::OwnedOptional { format: _, item } => {
523 self.parse_v3_inner(input, item).or(Ok(input))
524 }
525 #[cfg(feature = "alloc")]
526 FormatDescriptionV3Inner::OwnedFirst(items) => {
527 let mut first_err = None;
528
529 for item in items {
530 match self.parse_v3_inner(input, item) {
531 Ok(remaining_input) => return Ok(remaining_input),
532 Err(err) if first_err.is_none() => first_err = Some(err),
533 Err(_) => {}
534 }
535 }
536
537 match first_err {
538 Some(err) => Err(err),
539 None => Ok(input),
542 }
543 }
544 }
545 }
546
547 #[inline]
553 pub fn parse_item<'a>(
554 &mut self,
555 input: &'a [u8],
556 item: &impl sealed::AnyFormatItem,
557 ) -> Result<&'a [u8], error::ParseFromDescription> {
558 item.parse_item(self, input)
559 }
560
561 #[inline]
567 pub fn parse_items<'a>(
568 &mut self,
569 mut input: &'a [u8],
570 items: &[impl sealed::AnyFormatItem],
571 ) -> Result<&'a [u8], error::ParseFromDescription> {
572 let mut this = *self;
575 for item in items {
576 input = this.parse_item(input, item)?;
577 }
578 *self = this;
579 Ok(input)
580 }
581
582 #[inline]
584 pub fn parse_literal<'a>(
585 input: &'a [u8],
586 literal: &[u8],
587 ) -> Result<&'a [u8], error::ParseFromDescription> {
588 input
589 .strip_prefix(literal)
590 .ok_or(error::ParseFromDescription::InvalidLiteral)
591 }
592
593 #[inline]
596 pub fn parse_component<'a>(
597 &mut self,
598 input: &'a [u8],
599 component: Component,
600 ) -> Result<&'a [u8], error::ParseFromDescription> {
601 use error::ParseFromDescription::InvalidComponent;
602
603 let v3_fd: FormatDescriptionV3Inner<'static> = component.into();
604
605 if let FormatDescriptionV3Inner::Ignore(modifiers) = v3_fd {
607 return parse_ignore(input, modifiers)
608 .map(ParsedItem::<()>::into_inner)
609 .ok_or(InvalidComponent("ignore"));
610 }
611
612 self.parse_v3_inner(input, &v3_fd)
614 }
615}
616
617impl Parsed {
619 #[inline]
621 pub const fn year(&self) -> Option<i32> {
622 self.year.get_primitive()
623 }
624
625 #[inline]
630 pub const fn year_century(&self) -> Option<i16> {
631 self.year_century.get_primitive()
632 }
633
634 #[inline]
639 pub const fn year_century_is_negative(&self) -> Option<bool> {
640 match self.year_century() {
641 Some(_) => Some(self.year_century_is_negative),
642 None => None,
643 }
644 }
645
646 #[inline]
648 pub const fn year_last_two(&self) -> Option<u8> {
649 self.year_last_two.get_primitive()
650 }
651
652 #[inline]
654 pub const fn iso_year(&self) -> Option<i32> {
655 self.iso_year.get_primitive()
656 }
657
658 #[inline]
663 pub const fn iso_year_century(&self) -> Option<i16> {
664 self.iso_year_century.get_primitive()
665 }
666
667 #[inline]
672 pub const fn iso_year_century_is_negative(&self) -> Option<bool> {
673 match self.iso_year_century() {
674 Some(_) => Some(self.iso_year_century_is_negative),
675 None => None,
676 }
677 }
678
679 #[inline]
681 pub const fn iso_year_last_two(&self) -> Option<u8> {
682 self.iso_year_last_two.get_primitive()
683 }
684
685 #[inline]
687 pub const fn month(&self) -> Option<Month> {
688 self.month
689 }
690
691 #[inline]
693 pub const fn sunday_week_number(&self) -> Option<u8> {
694 self.sunday_week_number.get_primitive()
695 }
696
697 #[inline]
699 pub const fn monday_week_number(&self) -> Option<u8> {
700 self.monday_week_number.get_primitive()
701 }
702
703 #[inline]
705 pub const fn iso_week_number(&self) -> Option<NonZero<u8>> {
706 NonZero::new(const_try_opt!(self.iso_week_number.get_primitive()))
707 }
708
709 #[inline]
711 pub const fn weekday(&self) -> Option<Weekday> {
712 self.weekday
713 }
714
715 #[inline]
717 pub const fn ordinal(&self) -> Option<NonZero<u16>> {
718 NonZero::new(const_try_opt!(self.ordinal.get_primitive()))
719 }
720
721 #[inline]
723 pub const fn day(&self) -> Option<NonZero<u8>> {
724 NonZero::new(const_try_opt!(self.day.get_primitive()))
725 }
726
727 #[inline]
729 pub const fn hour_24(&self) -> Option<u8> {
730 self.hour_24.get_primitive()
731 }
732
733 #[inline]
735 pub const fn hour_12(&self) -> Option<NonZero<u8>> {
736 NonZero::new(const_try_opt!(self.hour_12.get_primitive()))
737 }
738
739 #[inline]
741 pub const fn hour_12_is_pm(&self) -> Option<bool> {
742 self.hour_12_is_pm
743 }
744
745 #[inline]
747 pub const fn minute(&self) -> Option<u8> {
748 self.minute.get_primitive()
749 }
750
751 #[inline]
753 pub const fn second(&self) -> Option<u8> {
754 self.second.get_primitive()
755 }
756
757 #[inline]
759 pub const fn subsecond(&self) -> Option<u32> {
760 self.subsecond.get_primitive()
761 }
762
763 #[inline]
765 pub const fn offset_hour(&self) -> Option<i8> {
766 self.offset_hour.get_primitive()
767 }
768
769 #[doc(hidden)]
771 #[deprecated(since = "0.3.8", note = "use `parsed.offset_minute_signed()` instead")]
772 #[inline]
773 pub const fn offset_minute(&self) -> Option<u8> {
774 Some(const_try_opt!(self.offset_minute_signed()).unsigned_abs())
775 }
776
777 #[inline]
779 pub const fn offset_minute_signed(&self) -> Option<i8> {
780 match (self.offset_minute.get_primitive(), self.offset_is_negative) {
781 (Some(offset_minute), true) => Some(-offset_minute),
782 (Some(offset_minute), _) => Some(offset_minute),
783 (None, _) => None,
784 }
785 }
786
787 #[doc(hidden)]
789 #[deprecated(since = "0.3.8", note = "use `parsed.offset_second_signed()` instead")]
790 #[inline]
791 pub const fn offset_second(&self) -> Option<u8> {
792 Some(const_try_opt!(self.offset_second_signed()).unsigned_abs())
793 }
794
795 #[inline]
797 pub const fn offset_second_signed(&self) -> Option<i8> {
798 match (self.offset_second.get_primitive(), self.offset_is_negative) {
799 (Some(offset_second), true) => Some(-offset_second),
800 (Some(offset_second), _) => Some(offset_second),
801 (None, _) => None,
802 }
803 }
804
805 #[inline]
807 pub const fn unix_timestamp_nanos(&self) -> Option<i128> {
808 self.unix_timestamp_nanos.get_primitive()
809 }
810}
811
812macro_rules! setters {
814 ($($name:ident $setter:ident $builder:ident $type:ty;)*) => {$(
815 #[doc = concat!("Set the `", stringify!($name), "` component.")]
816 #[inline]
817 pub const fn $setter(&mut self, value: $type) -> Option<()> {
818 match self.$builder(value) {
819 Some(value) => {
820 *self = value;
821 Some(())
822 },
823 None => None,
824 }
825 }
826 )*};
827}
828
829impl Parsed {
834 setters! {
835 year set_year with_year i32;
836 }
837
838 #[inline]
843 pub const fn set_year_century(&mut self, value: i16, is_negative: bool) -> Option<()> {
844 self.year_century = Option_ri16::Some(const_try_opt!(ri16::new(value)));
845 if value != 0 {
846 self.year_century_is_negative = value.is_negative();
847 } else {
848 self.year_century_is_negative = is_negative;
849 }
850 Some(())
851 }
852
853 setters! {
854 year_last_two set_year_last_two with_year_last_two u8;
855 iso_year set_iso_year with_iso_year i32;
856 iso_year_last_two set_iso_year_last_two with_iso_year_last_two u8;
857 }
858
859 #[inline]
864 pub const fn set_iso_year_century(&mut self, value: i16, is_negative: bool) -> Option<()> {
865 self.iso_year_century = Option_ri16::Some(const_try_opt!(ri16::new(value)));
866 if value != 0 {
867 self.iso_year_century_is_negative = value.is_negative();
868 } else {
869 self.iso_year_century_is_negative = is_negative;
870 }
871 Some(())
872 }
873
874 setters! {
875 month set_month with_month Month;
876 sunday_week_number set_sunday_week_number with_sunday_week_number u8;
877 monday_week_number set_monday_week_number with_monday_week_number u8;
878 iso_week_number set_iso_week_number with_iso_week_number NonZero<u8>;
879 weekday set_weekday with_weekday Weekday;
880 ordinal set_ordinal with_ordinal NonZero<u16>;
881 day set_day with_day NonZero<u8>;
882 hour_24 set_hour_24 with_hour_24 u8;
883 hour_12 set_hour_12 with_hour_12 NonZero<u8>;
884 hour_12_is_pm set_hour_12_is_pm with_hour_12_is_pm bool;
885 minute set_minute with_minute u8;
886 second set_second with_second u8;
887 subsecond set_subsecond with_subsecond u32;
888 offset_hour set_offset_hour with_offset_hour i8;
889 offset_minute set_offset_minute_signed with_offset_minute_signed i8;
890 offset_second set_offset_second_signed with_offset_second_signed i8;
891 unix_timestamp_nanos set_unix_timestamp_nanos with_unix_timestamp_nanos i128;
892 }
893
894 #[doc(hidden)]
896 #[deprecated(
897 since = "0.3.8",
898 note = "use `parsed.set_offset_minute_signed()` instead"
899 )]
900 #[inline]
901 pub const fn set_offset_minute(&mut self, value: u8) -> Option<()> {
902 if value > i8::MAX.cast_unsigned() {
903 None
904 } else {
905 self.set_offset_minute_signed(value.cast_signed())
906 }
907 }
908
909 #[doc(hidden)]
911 #[deprecated(
912 since = "0.3.8",
913 note = "use `parsed.set_offset_second_signed()` instead"
914 )]
915 #[inline]
916 pub const fn set_offset_second(&mut self, value: u8) -> Option<()> {
917 if value > i8::MAX.cast_unsigned() {
918 None
919 } else {
920 self.set_offset_second_signed(value.cast_signed())
921 }
922 }
923}
924
925impl Parsed {
930 #[inline]
932 pub const fn with_year(mut self, value: i32) -> Option<Self> {
933 self.year = Option_ri32::Some(const_try_opt!(ri32::new(value)));
934 Some(self)
935 }
936
937 #[inline]
942 pub const fn with_year_century(mut self, value: i16, is_negative: bool) -> Option<Self> {
943 self.year_century = Option_ri16::Some(const_try_opt!(ri16::new(value)));
944 if value != 0 {
945 self.year_century_is_negative = value.is_negative();
946 } else {
947 self.year_century_is_negative = is_negative;
948 }
949 Some(self)
950 }
951
952 #[inline]
954 pub const fn with_year_last_two(mut self, value: u8) -> Option<Self> {
955 self.year_last_two = Option_ru8::Some(const_try_opt!(ru8::new(value)));
956 Some(self)
957 }
958
959 #[inline]
961 pub const fn with_iso_year(mut self, value: i32) -> Option<Self> {
962 self.iso_year = Option_ri32::Some(const_try_opt!(ri32::new(value)));
963 Some(self)
964 }
965
966 #[inline]
971 pub const fn with_iso_year_century(mut self, value: i16, is_negative: bool) -> Option<Self> {
972 self.iso_year_century = Option_ri16::Some(const_try_opt!(ri16::new(value)));
973 if value != 0 {
974 self.iso_year_century_is_negative = value.is_negative();
975 } else {
976 self.iso_year_century_is_negative = is_negative;
977 }
978 Some(self)
979 }
980
981 #[inline]
983 pub const fn with_iso_year_last_two(mut self, value: u8) -> Option<Self> {
984 self.iso_year_last_two = Option_ru8::Some(const_try_opt!(ru8::new(value)));
985 Some(self)
986 }
987
988 #[inline]
990 pub const fn with_month(mut self, value: Month) -> Option<Self> {
991 self.month = Some(value);
992 Some(self)
993 }
994
995 #[inline]
997 pub const fn with_sunday_week_number(mut self, value: u8) -> Option<Self> {
998 self.sunday_week_number = Option_ru8::Some(const_try_opt!(ru8::new(value)));
999 Some(self)
1000 }
1001
1002 #[inline]
1004 pub const fn with_monday_week_number(mut self, value: u8) -> Option<Self> {
1005 self.monday_week_number = Option_ru8::Some(const_try_opt!(ru8::new(value)));
1006 Some(self)
1007 }
1008
1009 #[inline]
1011 pub const fn with_iso_week_number(mut self, value: NonZero<u8>) -> Option<Self> {
1012 self.iso_week_number = Option_ru8::Some(const_try_opt!(ru8::new(value.get())));
1013 Some(self)
1014 }
1015
1016 #[inline]
1018 pub const fn with_weekday(mut self, value: Weekday) -> Option<Self> {
1019 self.weekday = Some(value);
1020 Some(self)
1021 }
1022
1023 #[inline]
1025 pub const fn with_ordinal(mut self, value: NonZero<u16>) -> Option<Self> {
1026 self.ordinal = Option_ru16::Some(const_try_opt!(ru16::new(value.get())));
1027 Some(self)
1028 }
1029
1030 #[inline]
1032 pub const fn with_day(mut self, value: NonZero<u8>) -> Option<Self> {
1033 self.day = Option_ru8::Some(const_try_opt!(ru8::new(value.get())));
1034 Some(self)
1035 }
1036
1037 #[inline]
1039 pub const fn with_hour_24(mut self, value: u8) -> Option<Self> {
1040 self.hour_24 = Option_ru8::Some(const_try_opt!(ru8::new(value)));
1041 Some(self)
1042 }
1043
1044 #[inline]
1046 pub const fn with_hour_12(mut self, value: NonZero<u8>) -> Option<Self> {
1047 self.hour_12 = Option_ru8::Some(const_try_opt!(ru8::new(value.get())));
1048 Some(self)
1049 }
1050
1051 #[inline]
1053 pub const fn with_hour_12_is_pm(mut self, value: bool) -> Option<Self> {
1054 self.hour_12_is_pm = Some(value);
1055 Some(self)
1056 }
1057
1058 #[inline]
1060 pub const fn with_minute(mut self, value: u8) -> Option<Self> {
1061 self.minute = Option_ru8::Some(const_try_opt!(ru8::new(value)));
1062 Some(self)
1063 }
1064
1065 #[inline]
1067 pub const fn with_second(mut self, value: u8) -> Option<Self> {
1068 self.second = Option_ru8::Some(const_try_opt!(ru8::new(value)));
1069 Some(self)
1070 }
1071
1072 #[inline]
1074 pub const fn with_subsecond(mut self, value: u32) -> Option<Self> {
1075 self.subsecond = Option_ru32::Some(const_try_opt!(ru32::new(value)));
1076 Some(self)
1077 }
1078
1079 #[inline]
1081 pub const fn with_offset_hour(mut self, value: i8) -> Option<Self> {
1082 self.offset_hour = Option_ri8::Some(const_try_opt!(ri8::new(value)));
1083 Some(self)
1084 }
1085
1086 #[doc(hidden)]
1088 #[deprecated(
1089 since = "0.3.8",
1090 note = "use `parsed.with_offset_minute_signed()` instead"
1091 )]
1092 #[inline]
1093 pub const fn with_offset_minute(self, value: u8) -> Option<Self> {
1094 if value > i8::MAX.cast_unsigned() {
1095 None
1096 } else {
1097 self.with_offset_minute_signed(value.cast_signed())
1098 }
1099 }
1100
1101 #[inline]
1103 pub const fn with_offset_minute_signed(mut self, value: i8) -> Option<Self> {
1104 self.offset_minute = Option_ri8::Some(const_try_opt!(ri8::new(value)));
1105 Some(self)
1106 }
1107
1108 #[doc(hidden)]
1110 #[deprecated(
1111 since = "0.3.8",
1112 note = "use `parsed.with_offset_second_signed()` instead"
1113 )]
1114 #[inline]
1115 pub const fn with_offset_second(self, value: u8) -> Option<Self> {
1116 if value > i8::MAX.cast_unsigned() {
1117 None
1118 } else {
1119 self.with_offset_second_signed(value.cast_signed())
1120 }
1121 }
1122
1123 #[inline]
1125 pub const fn with_offset_second_signed(mut self, value: i8) -> Option<Self> {
1126 self.offset_second = Option_ri8::Some(const_try_opt!(ri8::new(value)));
1127 Some(self)
1128 }
1129
1130 #[inline]
1132 pub const fn with_unix_timestamp_nanos(mut self, value: i128) -> Option<Self> {
1133 self.unix_timestamp_nanos = Option_ri128::Some(const_try_opt!(ri128::new(value)));
1134 Some(self)
1135 }
1136}
1137
1138impl TryFrom<Parsed> for Date {
1139 type Error = error::TryFromParsed;
1140
1141 #[inline]
1142 fn try_from(mut parsed: Parsed) -> Result<Self, Self::Error> {
1143 macro_rules! match_ {
1145 (_ => $catch_all:expr $(,)?) => {
1146 $catch_all
1147 };
1148 (($($name:ident),* $(,)?) => $arm:expr, $($rest:tt)*) => {
1149 if let ($(Some($name)),*) = ($(parsed.$name()),*) {
1150 $arm
1151 } else {
1152 match_!($($rest)*)
1153 }
1154 };
1155 }
1156
1157 #[inline]
1160 const fn adjustment(year: i32) -> i16 {
1161 match unsafe { Date::__from_ordinal_date_unchecked(year, 1) }.weekday() {
1163 Weekday::Monday => 7,
1164 Weekday::Tuesday => 1,
1165 Weekday::Wednesday => 2,
1166 Weekday::Thursday => 3,
1167 Weekday::Friday => 4,
1168 Weekday::Saturday => 5,
1169 Weekday::Sunday => 6,
1170 }
1171 }
1172
1173 if let (None, Some(century), Some(is_negative), Some(last_two)) = (
1176 parsed.year(),
1177 parsed.year_century(),
1178 parsed.year_century_is_negative(),
1179 parsed.year_last_two(),
1180 ) {
1181 let year = if is_negative {
1182 100 * century.extend::<i32>() - last_two.cast_signed().extend::<i32>()
1183 } else {
1184 100 * century.extend::<i32>() + last_two.cast_signed().extend::<i32>()
1185 };
1186 parsed.year = Option_ri32::from(ri32::new(year));
1187 }
1188 if let (None, Some(century), Some(is_negative), Some(last_two)) = (
1189 parsed.iso_year(),
1190 parsed.iso_year_century(),
1191 parsed.iso_year_century_is_negative(),
1192 parsed.iso_year_last_two(),
1193 ) {
1194 let iso_year = if is_negative {
1195 100 * century.extend::<i32>() - last_two.cast_signed().extend::<i32>()
1196 } else {
1197 100 * century.extend::<i32>() + last_two.cast_signed().extend::<i32>()
1198 };
1199 parsed.iso_year = Option_ri32::from(ri32::new(iso_year));
1200 }
1201
1202 match_! {
1203 (year, ordinal) => Ok(Self::from_ordinal_date(year, ordinal.get())?),
1204 (year, month, day) => Ok(Self::from_calendar_date(year, month, day.get())?),
1205 (iso_year, iso_week_number, weekday) => Ok(Self::from_iso_week_date(
1206 iso_year,
1207 iso_week_number.get(),
1208 weekday,
1209 )?),
1210 (year, sunday_week_number, weekday) => Ok(Self::from_ordinal_date(
1211 year,
1212 (sunday_week_number.cast_signed().extend::<i16>() * 7
1213 + weekday.number_days_from_sunday().cast_signed().extend::<i16>()
1214 - adjustment(year)
1215 + 1).cast_unsigned(),
1216 )?),
1217 (year, monday_week_number, weekday) => Ok(Self::from_ordinal_date(
1218 year,
1219 (monday_week_number.cast_signed().extend::<i16>() * 7
1220 + weekday.number_days_from_monday().cast_signed().extend::<i16>()
1221 - adjustment(year)
1222 + 1).cast_unsigned(),
1223 )?),
1224 _ => Err(InsufficientInformation),
1225 }
1226 }
1227}
1228
1229impl TryFrom<Parsed> for Time {
1230 type Error = error::TryFromParsed;
1231
1232 #[inline]
1233 fn try_from(parsed: Parsed) -> Result<Self, Self::Error> {
1234 let hour = match (parsed.hour_24(), parsed.hour_12(), parsed.hour_12_is_pm()) {
1235 (Some(hour), _, _) => hour,
1236 (_, Some(hour), Some(false)) if hour.get() == 12 => 0,
1237 (_, Some(hour), Some(true)) if hour.get() == 12 => 12,
1238 (_, Some(hour), Some(false)) => hour.get(),
1239 (_, Some(hour), Some(true)) => hour.get() + 12,
1240 _ => return Err(InsufficientInformation),
1241 };
1242
1243 if parsed.hour_24().is_none()
1244 && parsed.hour_12().is_some()
1245 && parsed.hour_12_is_pm().is_some()
1246 && parsed.minute().is_none()
1247 && parsed.second().is_none()
1248 && parsed.subsecond().is_none()
1249 {
1250 return Ok(Self::from_hms_nano(hour, 0, 0, 0)?);
1251 }
1252
1253 match (parsed.minute(), parsed.second(), parsed.subsecond()) {
1255 (None, None, None) => Ok(Self::from_hms_nano(hour, 0, 0, 0)?),
1256 (Some(minute), None, None) => Ok(Self::from_hms_nano(hour, minute, 0, 0)?),
1257 (Some(minute), Some(second), None) => Ok(Self::from_hms_nano(hour, minute, second, 0)?),
1258 (Some(minute), Some(second), Some(subsecond)) => {
1259 Ok(Self::from_hms_nano(hour, minute, second, subsecond)?)
1260 }
1261 _ => Err(InsufficientInformation),
1262 }
1263 }
1264}
1265
1266#[inline]
1267fn utc_offset_try_from_parsed<const REQUIRED: bool>(
1268 parsed: Parsed,
1269) -> Result<UtcOffset, error::TryFromParsed> {
1270 let hour = match (REQUIRED, parsed.offset_hour()) {
1271 (true, None) => return Err(InsufficientInformation),
1273 (false, None) => return Ok(UtcOffset::UTC),
1276 (_, Some(hour)) => hour,
1278 };
1279 let minute = parsed.offset_minute_signed();
1280 let second = minute.and_then(|_| parsed.offset_second_signed());
1282
1283 let minute = minute.unwrap_or(0);
1284 let second = second.unwrap_or(0);
1285
1286 UtcOffset::from_hms(hour, minute, second).map_err(Into::into)
1287}
1288
1289impl TryFrom<Parsed> for UtcOffset {
1290 type Error = error::TryFromParsed;
1291
1292 #[inline]
1293 fn try_from(parsed: Parsed) -> Result<Self, Self::Error> {
1294 utc_offset_try_from_parsed::<true>(parsed)
1295 }
1296}
1297
1298impl TryFrom<Parsed> for PrimitiveDateTime {
1299 type Error = error::TryFromParsed;
1300
1301 #[inline]
1302 fn try_from(parsed: Parsed) -> Result<Self, Self::Error> {
1303 Ok(Self::new(parsed.try_into()?, parsed.try_into()?))
1304 }
1305}
1306
1307impl TryFrom<Parsed> for UtcDateTime {
1308 type Error = error::TryFromParsed;
1309
1310 #[inline]
1311 fn try_from(mut parsed: Parsed) -> Result<Self, Self::Error> {
1312 if let Some(timestamp) = parsed.unix_timestamp_nanos() {
1313 let mut value = Self::from_unix_timestamp_nanos(timestamp)?;
1314 if let Some(subsecond) = parsed.subsecond() {
1315 value = value.replace_nanosecond(subsecond)?;
1316 }
1317 return Ok(value);
1318 }
1319
1320 let leap_second_input = if parsed.leap_second_allowed && parsed.second() == Some(60) {
1324 if parsed.set_second(59).is_none() {
1325 bug!("59 is a valid second");
1326 }
1327 if parsed.set_subsecond(999_999_999).is_none() {
1328 bug!("999_999_999 is a valid subsecond");
1329 }
1330 true
1331 } else {
1332 false
1333 };
1334
1335 let dt = OffsetDateTime::new_in_offset(
1336 Date::try_from(parsed)?,
1337 Time::try_from(parsed)?,
1338 utc_offset_try_from_parsed::<false>(parsed)?,
1339 )
1340 .to_utc();
1341
1342 if leap_second_input && !dt.is_valid_leap_second_stand_in() {
1343 return Err(error::TryFromParsed::ComponentRange(
1344 error::ComponentRange::conditional("second"),
1345 ));
1346 }
1347 Ok(dt)
1348 }
1349}
1350
1351impl TryFrom<Parsed> for OffsetDateTime {
1352 type Error = error::TryFromParsed;
1353
1354 #[inline]
1355 fn try_from(mut parsed: Parsed) -> Result<Self, Self::Error> {
1356 if let Some(timestamp) = parsed.unix_timestamp_nanos() {
1357 let mut value = Self::from_unix_timestamp_nanos(timestamp)?;
1358 if let Some(subsecond) = parsed.subsecond() {
1359 value = value.replace_nanosecond(subsecond)?;
1360 }
1361 return Ok(value);
1362 }
1363
1364 let leap_second_input = if parsed.leap_second_allowed && parsed.second() == Some(60) {
1368 if parsed.set_second(59).is_none() {
1369 bug!("59 is a valid second");
1370 }
1371 if parsed.set_subsecond(999_999_999).is_none() {
1372 bug!("999_999_999 is a valid subsecond");
1373 }
1374 true
1375 } else {
1376 false
1377 };
1378
1379 let dt = Self::new_in_offset(
1380 Date::try_from(parsed)?,
1381 Time::try_from(parsed)?,
1382 UtcOffset::try_from(parsed)?,
1383 );
1384
1385 if leap_second_input && !dt.is_valid_leap_second_stand_in() {
1386 return Err(error::TryFromParsed::ComponentRange(
1387 error::ComponentRange::conditional("second"),
1388 ));
1389 }
1390 Ok(dt)
1391 }
1392}