Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  parsed.rs   Sprache: unbekannt

 
//! Information parsed from an input and format description.

use core::num::{NonZeroU16, NonZeroU8};

use deranged::{
    OptionRangedI128, OptionRangedI32, OptionRangedI8, OptionRangedU16, OptionRangedU32,
    OptionRangedU8, RangedI128, RangedI32, RangedI8, RangedU16, RangedU32, RangedU8,
};
use num_conv::prelude::*;

use crate::convert::{Day, Hour, Minute, Nanosecond, Second};
use crate::date::{MAX_YEAR, MIN_YEAR};
use crate::error::TryFromParsed::InsufficientInformation;
#[cfg(feature = "alloc")]
use crate::format_description::OwnedFormatItem;
use crate::format_description::{modifier, BorrowedFormatItem, Component};
use crate::internal_macros::{bug, const_try_opt};
use crate::parsing::component::{
    parse_day, parse_end, parse_hour, parse_ignore, parse_minute, parse_month, parse_offset_hour,
    parse_offset_minute, parse_offset_second, parse_ordinal, parse_period, parse_second,
    parse_subsecond, parse_unix_timestamp, parse_week_number, parse_weekday, parse_year, Period,
};
use crate::parsing::ParsedItem;
use crate::{error, Date, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcOffset, Weekday};

/// Sealed to prevent downstream implementations.
mod sealed {
    use super::*;

    /// A trait to allow `parse_item` to be generic.
    pub trait AnyFormatItem {
        /// Parse a single item, returning the remaining input on success.
        fn parse_item<'a>(
            &self,
            parsed: &mut Parsed,
            input: &'a [u8],
        ) -> Result<&'a [u8], error::ParseFromDescription>;
    }
}

impl sealed::AnyFormatItem for BorrowedFormatItem<'_> {
    fn parse_item<'a>(
        &self,
        parsed: &mut Parsed,
        input: &'a [u8],
    ) -> Result<&'a [u8], error::ParseFromDescription> {
        match self {
            Self::Literal(literal) => Parsed::parse_literal(input, literal),
            Self::Component(component) => parsed.parse_component(input, *component),
            Self::Compound(compound) => parsed.parse_items(input, compound),
            Self::Optional(item) => parsed.parse_item(input, *item).or(Ok(input)),
            Self::First(items) => {
                let mut first_err = None;

                for item in items.iter() {
                    match parsed.parse_item(input, item) {
                        Ok(remaining_input) => return Ok(remaining_input),
                        Err(err) if first_err.is_none() => first_err = Some(err),
                        Err(_) => {}
                    }
                }

                match first_err {
                    Some(err) => Err(err),
                    // This location will be reached if the slice is empty, skipping the `for` loop.
                    // As this case is expected to be uncommon, there's no need to check up front.
                    None => Ok(input),
                }
            }
        }
    }
}

#[cfg(feature = "alloc")]
impl sealed::AnyFormatItem for OwnedFormatItem {
    fn parse_item<'a>(
        &self,
        parsed: &mut Parsed,
        input: &'a [u8],
    ) -> Result<&'a [u8], error::ParseFromDescription> {
        match self {
            Self::Literal(literal) => Parsed::parse_literal(input, literal),
            Self::Component(component) => parsed.parse_component(input, *component),
            Self::Compound(compound) => parsed.parse_items(input, compound),
            Self::Optional(item) => parsed.parse_item(input, item.as_ref()).or(Ok(input)),
            Self::First(items) => {
                let mut first_err = None;

                for item in items.iter() {
                    match parsed.parse_item(input, item) {
                        Ok(remaining_input) => return Ok(remaining_input),
                        Err(err) if first_err.is_none() => first_err = Some(err),
                        Err(_) => {}
                    }
                }

                match first_err {
                    Some(err) => Err(err),
                    // This location will be reached if the slice is empty, skipping the `for` loop.
                    // As this case is expected to be uncommon, there's no need to check up front.
                    None => Ok(input),
                }
            }
        }
    }
}

/// All information parsed.
///
/// This information is directly used to construct the final values.
///
/// Most users will not need think about this struct in any way. It is public to allow for manual
/// control over values, in the instance that the default parser is insufficient.
#[derive(Debug, Clone, Copy)]
pub struct Parsed {
    /// Calendar year.
    year: OptionRangedI32<{ MIN_YEAR }, { MAX_YEAR }>,
    /// The last two digits of the calendar year.
    year_last_two: OptionRangedU8<0, 99>,
    /// Year of the [ISO week date](https://en.wikipedia.org/wiki/ISO_week_date).
    iso_year: OptionRangedI32<{ MIN_YEAR }, { MAX_YEAR }>,
    /// The last two digits of the ISO week year.
    iso_year_last_two: OptionRangedU8<0, 99>,
    /// Month of the year.
    month: Option<Month>,
    /// Week of the year, where week one begins on the first Sunday of the calendar year.
    sunday_week_number: OptionRangedU8<0, 53>,
    /// Week of the year, where week one begins on the first Monday of the calendar year.
    monday_week_number: OptionRangedU8<0, 53>,
    /// Week of the year, where week one is the Monday-to-Sunday period containing January 4.
    iso_week_number: OptionRangedU8<1, 53>,
    /// Day of the week.
    weekday: Option<Weekday>,
    /// Day of the year.
    ordinal: OptionRangedU16<1, 366>,
    /// Day of the month.
    day: OptionRangedU8<1, 31>,
    /// Hour within the day.
    hour_24: OptionRangedU8<0, { Hour::per(Day) - 1 }>,
    /// Hour within the 12-hour period (midnight to noon or vice versa). This is typically used in
    /// conjunction with AM/PM, which is indicated by the `hour_12_is_pm` field.
    hour_12: OptionRangedU8<1, 12>,
    /// Whether the `hour_12` field indicates a time that "PM".
    hour_12_is_pm: Option<bool>,
    /// Minute within the hour.
    // minute: MaybeUninit<u8>,
    minute: OptionRangedU8<0, { Minute::per(Hour) - 1 }>,
    /// Second within the minute.
    // do not subtract one, as leap seconds may be allowed
    second: OptionRangedU8<0, { Second::per(Minute) }>,
    /// Nanosecond within the second.
    subsecond: OptionRangedU32<0, { Nanosecond::per(Second) - 1 }>,
    /// Whole hours of the UTC offset.
    offset_hour: OptionRangedI8<-23, 23>,
    /// Minutes within the hour of the UTC offset.
    offset_minute:
        OptionRangedI8<{ -((Minute::per(Hour) - 1) as i8) }, { (Minute::per(Hour) - 1) as _ }>,
    /// Seconds within the minute of the UTC offset.
    offset_second:
        OptionRangedI8<{ -((Second::per(Minute) - 1) as i8) }, { (Second::per(Minute) - 1) as _ }>,
    /// The Unix timestamp in nanoseconds.
    unix_timestamp_nanos: OptionRangedI128<
        {
            OffsetDateTime::new_in_offset(Date::MIN, Time::MIDNIGHT, UtcOffset::UTC)
                .unix_timestamp_nanos()
        },
        {
            OffsetDateTime::new_in_offset(Date::MAX, Time::MAX, UtcOffset::UTC)
                .unix_timestamp_nanos()
        },
    >,
    /// Indicates whether the [`UtcOffset`] is negative. This information is obtained when parsing
    /// the offset hour, but may not otherwise be stored due to "-0" being equivalent to "0".
    offset_is_negative: Option<bool>,
    /// Indicates whether a leap second is permitted to be parsed. This is required by some
    /// well-known formats.
    pub(super) leap_second_allowed: bool,
}

impl Default for Parsed {
    fn default() -> Self {
        Self::new()
    }
}

impl Parsed {
    /// Create a new instance of `Parsed` with no information known.
    pub const fn new() -> Self {
        Self {
            year: OptionRangedI32::None,
            year_last_two: OptionRangedU8::None,
            iso_year: OptionRangedI32::None,
            iso_year_last_two: OptionRangedU8::None,
            month: None,
            sunday_week_number: OptionRangedU8::None,
            monday_week_number: OptionRangedU8::None,
            iso_week_number: OptionRangedU8::None,
            weekday: None,
            ordinal: OptionRangedU16::None,
            day: OptionRangedU8::None,
            hour_24: OptionRangedU8::None,
            hour_12: OptionRangedU8::None,
            hour_12_is_pm: None,
            minute: OptionRangedU8::None,
            second: OptionRangedU8::None,
            subsecond: OptionRangedU32::None,
            offset_hour: OptionRangedI8::None,
            offset_minute: OptionRangedI8::None,
            offset_second: OptionRangedI8::None,
            unix_timestamp_nanos: OptionRangedI128::None,
            offset_is_negative: None,
            leap_second_allowed: false,
        }
    }

    /// Parse a single [`BorrowedFormatItem`] or [`OwnedFormatItem`], mutating the struct. The
    /// remaining input is returned as the `Ok` value.
    ///
    /// If a [`BorrowedFormatItem::Optional`] or [`OwnedFormatItem::Optional`] is passed, parsing
    /// will not fail; the input will be returned as-is if the expected format is not present.
    pub fn parse_item<'a>(
        &mut self,
        input: &'a [u8],
        item: &impl sealed::AnyFormatItem,
    ) -> Result<&'a [u8], error::ParseFromDescription> {
        item.parse_item(self, input)
    }

    /// Parse a sequence of [`BorrowedFormatItem`]s or [`OwnedFormatItem`]s, mutating the struct.
    /// The remaining input is returned as the `Ok` value.
    ///
    /// This method will fail if any of the contained [`BorrowedFormatItem`]s or
    /// [`OwnedFormatItem`]s fail to parse. `self` will not be mutated in this instance.
    pub fn parse_items<'a>(
        &mut self,
        mut input: &'a [u8],
        items: &[impl sealed::AnyFormatItem],
    ) -> Result<&'a [u8], error::ParseFromDescription> {
        // Make a copy that we can mutate. It will only be set to the user's copy if everything
        // succeeds.
        let mut this = *self;
        for item in items {
            input = this.parse_item(input, item)?;
        }
        *self = this;
        Ok(input)
    }

    /// Parse a literal byte sequence. The remaining input is returned as the `Ok` value.
    pub fn parse_literal<'a>(
        input: &'a [u8],
        literal: &[u8],
    ) -> Result<&'a [u8], error::ParseFromDescription> {
        input
            .strip_prefix(literal)
            .ok_or(error::ParseFromDescription::InvalidLiteral)
    }

    /// Parse a single component, mutating the struct. The remaining input is returned as the `Ok`
    /// value.
    pub fn parse_component<'a>(
        &mut self,
        input: &'a [u8],
        component: Component,
    ) -> Result<&'a [u8], error::ParseFromDescription> {
        use error::ParseFromDescription::InvalidComponent;

        match component {
            Component::Day(modifiers) => parse_day(input, modifiers)
                .and_then(|parsed| parsed.consume_value(|value| self.set_day(value)))
                .ok_or(InvalidComponent("day")),
            Component::Month(modifiers) => parse_month(input, modifiers)
                .and_then(|parsed| parsed.consume_value(|value| self.set_month(value)))
                .ok_or(InvalidComponent("month")),
            Component::Ordinal(modifiers) => parse_ordinal(input, modifiers)
                .and_then(|parsed| parsed.consume_value(|value| self.set_ordinal(value)))
                .ok_or(InvalidComponent("ordinal")),
            Component::Weekday(modifiers) => parse_weekday(input, modifiers)
                .and_then(|parsed| parsed.consume_value(|value| self.set_weekday(value)))
                .ok_or(InvalidComponent("weekday")),
            Component::WeekNumber(modifiers) => {
                let ParsedItem(remaining, value) =
                    parse_week_number(input, modifiers).ok_or(InvalidComponent("week number"))?;
                match modifiers.repr {
                    modifier::WeekNumberRepr::Iso => {
                        NonZeroU8::new(value).and_then(|value| self.set_iso_week_number(value))
                    }
                    modifier::WeekNumberRepr::Sunday => self.set_sunday_week_number(value),
                    modifier::WeekNumberRepr::Monday => self.set_monday_week_number(value),
                }
                .ok_or(InvalidComponent("week number"))?;
                Ok(remaining)
            }
            Component::Year(modifiers) => {
                let ParsedItem(remaining, value) =
                    parse_year(input, modifiers).ok_or(InvalidComponent("year"))?;
                match (modifiers.iso_week_based, modifiers.repr) {
                    (false, modifier::YearRepr::Full) => self.set_year(value),
                    (false, modifier::YearRepr::LastTwo) => {
                        self.set_year_last_two(value.cast_unsigned().truncate())
                    }
                    (true, modifier::YearRepr::Full) => self.set_iso_year(value),
                    (true, modifier::YearRepr::LastTwo) => {
                        self.set_iso_year_last_two(value.cast_unsigned().truncate())
                    }
                }
                .ok_or(InvalidComponent("year"))?;
                Ok(remaining)
            }
            Component::Hour(modifiers) => {
                let ParsedItem(remaining, value) =
                    parse_hour(input, modifiers).ok_or(InvalidComponent("hour"))?;
                if modifiers.is_12_hour_clock {
                    NonZeroU8::new(value).and_then(|value| self.set_hour_12(value))
                } else {
                    self.set_hour_24(value)
                }
                .ok_or(InvalidComponent("hour"))?;
                Ok(remaining)
            }
            Component::Minute(modifiers) => parse_minute(input, modifiers)
                .and_then(|parsed| parsed.consume_value(|value| self.set_minute(value)))
                .ok_or(InvalidComponent("minute")),
            Component::Period(modifiers) => parse_period(input, modifiers)
                .and_then(|parsed| {
                    parsed.consume_value(|value| self.set_hour_12_is_pm(value == Period::Pm))
                })
                .ok_or(InvalidComponent("period")),
            Component::Second(modifiers) => parse_second(input, modifiers)
                .and_then(|parsed| parsed.consume_value(|value| self.set_second(value)))
                .ok_or(InvalidComponent("second")),
            Component::Subsecond(modifiers) => parse_subsecond(input, modifiers)
                .and_then(|parsed| parsed.consume_value(|value| self.set_subsecond(value)))
                .ok_or(InvalidComponent("subsecond")),
            Component::OffsetHour(modifiers) => parse_offset_hour(input, modifiers)
                .and_then(|parsed| {
                    parsed.consume_value(|(value, is_negative)| {
                        self.set_offset_hour(value)?;
                        self.offset_is_negative = Some(is_negative);
                        Some(())
                    })
                })
                .ok_or(InvalidComponent("offset hour")),
            Component::OffsetMinute(modifiers) => parse_offset_minute(input, modifiers)
                .and_then(|parsed| {
                    parsed.consume_value(|value| self.set_offset_minute_signed(value))
                })
                .ok_or(InvalidComponent("offset minute")),
            Component::OffsetSecond(modifiers) => parse_offset_second(input, modifiers)
                .and_then(|parsed| {
                    parsed.consume_value(|value| self.set_offset_second_signed(value))
                })
                .ok_or(InvalidComponent("offset second")),
            Component::Ignore(modifiers) => parse_ignore(input, modifiers)
                .map(ParsedItem::<()>::into_inner)
                .ok_or(InvalidComponent("ignore")),
            Component::UnixTimestamp(modifiers) => parse_unix_timestamp(input, modifiers)
                .and_then(|parsed| {
                    parsed.consume_value(|value| self.set_unix_timestamp_nanos(value))
                })
                .ok_or(InvalidComponent("unix_timestamp")),
            Component::End(modifiers) => parse_end(input, modifiers)
                .map(ParsedItem::<()>::into_inner)
                .ok_or(error::ParseFromDescription::UnexpectedTrailingCharacters),
        }
    }
}

/// Getter methods
impl Parsed {
    /// Obtain the `year` component.
    pub const fn year(&self) -> Option<i32> {
        self.year.get_primitive()
    }

    /// Obtain the `year_last_two` component.
    pub const fn year_last_two(&self) -> Option<u8> {
        self.year_last_two.get_primitive()
    }

    /// Obtain the `iso_year` component.
    pub const fn iso_year(&self) -> Option<i32> {
        self.iso_year.get_primitive()
    }

    /// Obtain the `iso_year_last_two` component.
    pub const fn iso_year_last_two(&self) -> Option<u8> {
        self.iso_year_last_two.get_primitive()
    }

    /// Obtain the `month` component.
    pub const fn month(&self) -> Option<Month> {
        self.month
    }

    /// Obtain the `sunday_week_number` component.
    pub const fn sunday_week_number(&self) -> Option<u8> {
        self.sunday_week_number.get_primitive()
    }

    /// Obtain the `monday_week_number` component.
    pub const fn monday_week_number(&self) -> Option<u8> {
        self.monday_week_number.get_primitive()
    }

    /// Obtain the `iso_week_number` component.
    pub const fn iso_week_number(&self) -> Option<NonZeroU8> {
        NonZeroU8::new(const_try_opt!(self.iso_week_number.get_primitive()))
    }

    /// Obtain the `weekday` component.
    pub const fn weekday(&self) -> Option<Weekday> {
        self.weekday
    }

    /// Obtain the `ordinal` component.
    pub const fn ordinal(&self) -> Option<NonZeroU16> {
        NonZeroU16::new(const_try_opt!(self.ordinal.get_primitive()))
    }

    /// Obtain the `day` component.
    pub const fn day(&self) -> Option<NonZeroU8> {
        NonZeroU8::new(const_try_opt!(self.day.get_primitive()))
    }

    /// Obtain the `hour_24` component.
    pub const fn hour_24(&self) -> Option<u8> {
        self.hour_24.get_primitive()
    }

    /// Obtain the `hour_12` component.
    pub const fn hour_12(&self) -> Option<NonZeroU8> {
        NonZeroU8::new(const_try_opt!(self.hour_12.get_primitive()))
    }

    /// Obtain the `hour_12_is_pm` component.
    pub const fn hour_12_is_pm(&self) -> Option<bool> {
        self.hour_12_is_pm
    }

    /// Obtain the `minute` component.
    pub const fn minute(&self) -> Option<u8> {
        self.minute.get_primitive()
    }

    /// Obtain the `second` component.
    pub const fn second(&self) -> Option<u8> {
        self.second.get_primitive()
    }

    /// Obtain the `subsecond` component.
    pub const fn subsecond(&self) -> Option<u32> {
        self.subsecond.get_primitive()
    }

    /// Obtain the `offset_hour` component.
    pub const fn offset_hour(&self) -> Option<i8> {
        self.offset_hour.get_primitive()
    }

    /// Obtain the absolute value of the `offset_minute` component.
    #[doc(hidden)]
    #[deprecated(since = "0.3.8", note = "use `parsed.offset_minute_signed()` instead")]
    pub const fn offset_minute(&self) -> Option<u8> {
        Some(const_try_opt!(self.offset_minute_signed()).unsigned_abs())
    }

    /// Obtain the `offset_minute` component.
    pub const fn offset_minute_signed(&self) -> Option<i8> {
        match (self.offset_minute.get_primitive(), self.offset_is_negative) {
            (Some(offset_minute), Some(true)) => Some(-offset_minute),
            (Some(offset_minute), _) => Some(offset_minute),
            (None, _) => None,
        }
    }

    /// Obtain the absolute value of the `offset_second` component.
    #[doc(hidden)]
    #[deprecated(since = "0.3.8", note = "use `parsed.offset_second_signed()` instead")]
    pub const fn offset_second(&self) -> Option<u8> {
        Some(const_try_opt!(self.offset_second_signed()).unsigned_abs())
    }

    /// Obtain the `offset_second` component.
    pub const fn offset_second_signed(&self) -> Option<i8> {
        match (self.offset_second.get_primitive(), self.offset_is_negative) {
            (Some(offset_second), Some(true)) => Some(-offset_second),
            (Some(offset_second), _) => Some(offset_second),
            (None, _) => None,
        }
    }

    /// Obtain the `unix_timestamp_nanos` component.
    pub const fn unix_timestamp_nanos(&self) -> Option<i128> {
        self.unix_timestamp_nanos.get_primitive()
    }
}

/// Generate setters based on the builders.
macro_rules! setters {
    ($($name:ident $setter:ident $builder:ident $type:ty;)*) => {$(
        #[doc = concat!("Set the `", stringify!($setter), "` component.")]
        pub fn $setter(&mut self, value: $type) -> Option<()> {
            *self = self.$builder(value)?;
            Some(())
        }
    )*};
}

/// Setter methods
///
/// All setters return `Option<()>`, which is `Some` if the value was set, and `None` if not. The
/// setters _may_ fail if the value is invalid, though behavior is not guaranteed.
impl Parsed {
    setters! {
        year set_year with_year i32;
        year_last_two set_year_last_two with_year_last_two u8;
        iso_year set_iso_year with_iso_year i32;
        iso_year_last_two set_iso_year_last_two with_iso_year_last_two u8;
        month set_month with_month Month;
        sunday_week_number set_sunday_week_number with_sunday_week_number u8;
        monday_week_number set_monday_week_number with_monday_week_number u8;
        iso_week_number set_iso_week_number with_iso_week_number NonZeroU8;
        weekday set_weekday with_weekday Weekday;
        ordinal set_ordinal with_ordinal NonZeroU16;
        day set_day with_day NonZeroU8;
        hour_24 set_hour_24 with_hour_24 u8;
        hour_12 set_hour_12 with_hour_12 NonZeroU8;
        hour_12_is_pm set_hour_12_is_pm with_hour_12_is_pm bool;
        minute set_minute with_minute u8;
        second set_second with_second u8;
        subsecond set_subsecond with_subsecond u32;
        offset_hour set_offset_hour with_offset_hour i8;
        offset_minute set_offset_minute_signed with_offset_minute_signed i8;
        offset_second set_offset_second_signed with_offset_second_signed i8;
        unix_timestamp_nanos set_unix_timestamp_nanos with_unix_timestamp_nanos i128;
    }

    /// Set the `offset_minute` component.
    #[doc(hidden)]
    #[deprecated(
        since = "0.3.8",
        note = "use `parsed.set_offset_minute_signed()` instead"
    )]
    pub fn set_offset_minute(&mut self, value: u8) -> Option<()> {
        if value > i8::MAX.cast_unsigned() {
            None
        } else {
            self.set_offset_minute_signed(value.cast_signed())
        }
    }

    /// Set the `offset_minute` component.
    #[doc(hidden)]
    #[deprecated(
        since = "0.3.8",
        note = "use `parsed.set_offset_second_signed()` instead"
    )]
    pub fn set_offset_second(&mut self, value: u8) -> Option<()> {
        if value > i8::MAX.cast_unsigned() {
            None
        } else {
            self.set_offset_second_signed(value.cast_signed())
        }
    }
}

/// Builder methods
///
/// All builder methods return `Option<Self>`, which is `Some` if the value was set, and `None` if
/// not. The builder methods _may_ fail if the value is invalid, though behavior is not guaranteed.
impl Parsed {
    /// Set the `year` component and return `self`.
    pub const fn with_year(mut self, value: i32) -> Option<Self> {
        self.year = OptionRangedI32::Some(const_try_opt!(RangedI32::new(value)));
        Some(self)
    }

    /// Set the `year_last_two` component and return `self`.
    pub const fn with_year_last_two(mut self, value: u8) -> Option<Self> {
        self.year_last_two = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
        Some(self)
    }

    /// Set the `iso_year` component and return `self`.
    pub const fn with_iso_year(mut self, value: i32) -> Option<Self> {
        self.iso_year = OptionRangedI32::Some(const_try_opt!(RangedI32::new(value)));
        Some(self)
    }

    /// Set the `iso_year_last_two` component and return `self`.
    pub const fn with_iso_year_last_two(mut self, value: u8) -> Option<Self> {
        self.iso_year_last_two = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
        Some(self)
    }

    /// Set the `month` component and return `self`.
    pub const fn with_month(mut self, value: Month) -> Option<Self> {
        self.month = Some(value);
        Some(self)
    }

    /// Set the `sunday_week_number` component and return `self`.
    pub const fn with_sunday_week_number(mut self, value: u8) -> Option<Self> {
        self.sunday_week_number = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
        Some(self)
    }

    /// Set the `monday_week_number` component and return `self`.
    pub const fn with_monday_week_number(mut self, value: u8) -> Option<Self> {
        self.monday_week_number = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
        Some(self)
    }

    /// Set the `iso_week_number` component and return `self`.
    pub const fn with_iso_week_number(mut self, value: NonZeroU8) -> Option<Self> {
        self.iso_week_number = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value.get())));
        Some(self)
    }

    /// Set the `weekday` component and return `self`.
    pub const fn with_weekday(mut self, value: Weekday) -> Option<Self> {
        self.weekday = Some(value);
        Some(self)
    }

    /// Set the `ordinal` component and return `self`.
    pub const fn with_ordinal(mut self, value: NonZeroU16) -> Option<Self> {
        self.ordinal = OptionRangedU16::Some(const_try_opt!(RangedU16::new(value.get())));
        Some(self)
    }

    /// Set the `day` component and return `self`.
    pub const fn with_day(mut self, value: NonZeroU8) -> Option<Self> {
        self.day = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value.get())));
        Some(self)
    }

    /// Set the `hour_24` component and return `self`.
    pub const fn with_hour_24(mut self, value: u8) -> Option<Self> {
        self.hour_24 = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
        Some(self)
    }

    /// Set the `hour_12` component and return `self`.
    pub const fn with_hour_12(mut self, value: NonZeroU8) -> Option<Self> {
        self.hour_12 = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value.get())));
        Some(self)
    }

    /// Set the `hour_12_is_pm` component and return `self`.
    pub const fn with_hour_12_is_pm(mut self, value: bool) -> Option<Self> {
        self.hour_12_is_pm = Some(value);
        Some(self)
    }

    /// Set the `minute` component and return `self`.
    pub const fn with_minute(mut self, value: u8) -> Option<Self> {
        self.minute = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
        Some(self)
    }

    /// Set the `second` component and return `self`.
    pub const fn with_second(mut self, value: u8) -> Option<Self> {
        self.second = OptionRangedU8::Some(const_try_opt!(RangedU8::new(value)));
        Some(self)
    }

    /// Set the `subsecond` component and return `self`.
    pub const fn with_subsecond(mut self, value: u32) -> Option<Self> {
        self.subsecond = OptionRangedU32::Some(const_try_opt!(RangedU32::new(value)));
        Some(self)
    }

    /// Set the `offset_hour` component and return `self`.
    pub const fn with_offset_hour(mut self, value: i8) -> Option<Self> {
        self.offset_hour = OptionRangedI8::Some(const_try_opt!(RangedI8::new(value)));
        Some(self)
    }

    /// Set the `offset_minute` component and return `self`.
    #[doc(hidden)]
    #[deprecated(
        since = "0.3.8",
        note = "use `parsed.with_offset_minute_signed()` instead"
    )]
    pub const fn with_offset_minute(self, value: u8) -> Option<Self> {
        if value > i8::MAX as u8 {
            None
        } else {
            self.with_offset_minute_signed(value as _)
        }
    }

    /// Set the `offset_minute` component and return `self`.
    pub const fn with_offset_minute_signed(mut self, value: i8) -> Option<Self> {
        self.offset_minute = OptionRangedI8::Some(const_try_opt!(RangedI8::new(value)));
        Some(self)
    }

    /// Set the `offset_minute` component and return `self`.
    #[doc(hidden)]
    #[deprecated(
        since = "0.3.8",
        note = "use `parsed.with_offset_second_signed()` instead"
    )]
    pub const fn with_offset_second(self, value: u8) -> Option<Self> {
        if value > i8::MAX as u8 {
            None
        } else {
            self.with_offset_second_signed(value as _)
        }
    }

    /// Set the `offset_second` component and return `self`.
    pub const fn with_offset_second_signed(mut self, value: i8) -> Option<Self> {
        self.offset_second = OptionRangedI8::Some(const_try_opt!(RangedI8::new(value)));
        Some(self)
    }

    /// Set the `unix_timestamp_nanos` component and return `self`.
    pub const fn with_unix_timestamp_nanos(mut self, value: i128) -> Option<Self> {
        self.unix_timestamp_nanos = OptionRangedI128::Some(const_try_opt!(RangedI128::new(value)));
        Some(self)
    }
}

impl TryFrom<Parsed> for Date {
    type Error = error::TryFromParsed;

    fn try_from(parsed: Parsed) -> Result<Self, Self::Error> {
        /// Match on the components that need to be present.
        macro_rules! match_ {
            (_ => $catch_all:expr $(,)?) => {
                $catch_all
            };
            (($($name:ident),* $(,)?) => $arm:expr, $($rest:tt)*) => {
                if let ($(Some($name)),*) = ($(parsed.$name()),*) {
                    $arm
                } else {
                    match_!($($rest)*)
                }
            };
        }

        /// Get the value needed to adjust the ordinal day for Sunday and Monday-based week
        /// numbering.
        const fn adjustment(year: i32) -> i16 {
            // Safety: `ordinal` is not zero.
            match unsafe { Date::__from_ordinal_date_unchecked(year, 1) }.weekday() {
                Weekday::Monday => 7,
                Weekday::Tuesday => 1,
                Weekday::Wednesday => 2,
                Weekday::Thursday => 3,
                Weekday::Friday => 4,
                Weekday::Saturday => 5,
                Weekday::Sunday => 6,
            }
        }

        // TODO Only the basics have been covered. There are many other valid values that are not
        // currently constructed from the information known.

        match_! {
            (year, ordinal) => Ok(Self::from_ordinal_date(year, ordinal.get())?),
            (year, month, day) => Ok(Self::from_calendar_date(year, month, day.get())?),
            (iso_year, iso_week_number, weekday) => Ok(Self::from_iso_week_date(
                iso_year,
                iso_week_number.get(),
                weekday,
            )?),
            (year, sunday_week_number, weekday) => Ok(Self::from_ordinal_date(
                year,
                (sunday_week_number.cast_signed().extend::<i16>() * 7
                    + weekday.number_days_from_sunday().cast_signed().extend::<i16>()
                    - adjustment(year)
                    + 1).cast_unsigned(),
            )?),
            (year, monday_week_number, weekday) => Ok(Self::from_ordinal_date(
                year,
                (monday_week_number.cast_signed().extend::<i16>() * 7
                    + weekday.number_days_from_monday().cast_signed().extend::<i16>()
                    - adjustment(year)
                    + 1).cast_unsigned(),
            )?),
            _ => Err(InsufficientInformation),
        }
    }
}

impl TryFrom<Parsed> for Time {
    type Error = error::TryFromParsed;

    fn try_from(parsed: Parsed) -> Result<Self, Self::Error> {
        let hour = match (parsed.hour_24(), parsed.hour_12(), parsed.hour_12_is_pm()) {
            (Some(hour), _, _) => hour,
            (_, Some(hour), Some(false)) if hour.get() == 12 => 0,
            (_, Some(hour), Some(true)) if hour.get() == 12 => 12,
            (_, Some(hour), Some(false)) => hour.get(),
            (_, Some(hour), Some(true)) => hour.get() + 12,
            _ => return Err(InsufficientInformation),
        };

        if parsed.hour_24().is_none()
            && parsed.hour_12().is_some()
            && parsed.hour_12_is_pm().is_some()
            && parsed.minute().is_none()
            && parsed.second().is_none()
            && parsed.subsecond().is_none()
        {
            return Ok(Self::from_hms_nano(hour, 0, 0, 0)?);
        }

        // Reject combinations such as hour-second with minute omitted.
        match (parsed.minute(), parsed.second(), parsed.subsecond()) {
            (None, None, None) => Ok(Self::from_hms_nano(hour, 0, 0, 0)?),
            (Some(minute), None, None) => Ok(Self::from_hms_nano(hour, minute, 0, 0)?),
            (Some(minute), Some(second), None) => Ok(Self::from_hms_nano(hour, minute, second, 0)?),
            (Some(minute), Some(second), Some(subsecond)) => {
                Ok(Self::from_hms_nano(hour, minute, second, subsecond)?)
            }
            _ => Err(InsufficientInformation),
        }
    }
}

impl TryFrom<Parsed> for UtcOffset {
    type Error = error::TryFromParsed;

    fn try_from(parsed: Parsed) -> Result<Self, Self::Error> {
        let hour = parsed.offset_hour().ok_or(InsufficientInformation)?;
        let minute = parsed.offset_minute_signed().unwrap_or(0);
        let second = parsed.offset_second_signed().unwrap_or(0);

        Self::from_hms(hour, minute, second).map_err(|mut err| {
            // Provide the user a more accurate error.
            if err.name == "hours" {
                err.name = "offset hour";
            } else if err.name == "minutes" {
                err.name = "offset minute";
            } else if err.name == "seconds" {
                err.name = "offset second";
            }
            err.into()
        })
    }
}

impl TryFrom<Parsed> for PrimitiveDateTime {
    type Error = error::TryFromParsed;

    fn try_from(parsed: Parsed) -> Result<Self, Self::Error> {
        Ok(Self::new(parsed.try_into()?, parsed.try_into()?))
    }
}

impl TryFrom<Parsed> for OffsetDateTime {
    type Error = error::TryFromParsed;

    fn try_from(mut parsed: Parsed) -> Result<Self, Self::Error> {
        if let Some(timestamp) = parsed.unix_timestamp_nanos() {
            let mut value = Self::from_unix_timestamp_nanos(timestamp)?;
            if let Some(subsecond) = parsed.subsecond() {
                value = value.replace_nanosecond(subsecond)?;
            }
            return Ok(value);
        }

        // Some well-known formats explicitly allow leap seconds. We don't currently support them,
        // so treat it as the nearest preceding moment that can be represented. Because leap seconds
        // always fall at the end of a month UTC, reject any that are at other times.
        let leap_second_input = if parsed.leap_second_allowed && parsed.second() == Some(60) {
            if parsed.set_second(59).is_none() {
                bug!("59 is a valid second");
            }
            if parsed.set_subsecond(999_999_999).is_none() {
                bug!("999_999_999 is a valid subsecond");
            }
            true
        } else {
            false
        };

        let dt = Self::new_in_offset(
            Date::try_from(parsed)?,
            Time::try_from(parsed)?,
            UtcOffset::try_from(parsed)?,
        );

        if leap_second_input && !dt.is_valid_leap_second_stand_in() {
            return Err(error::TryFromParsed::ComponentRange(
                error::ComponentRange {
                    name: "second",
                    minimum: 0,
                    maximum: 59,
                    value: 60,
                    conditional_range: true,
                },
            ));
        }
        Ok(dt)
    }
}

[ Dauer der Verarbeitung: 0.34 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge