/// A type that can be parsed. #[cfg_attr(__time_03_docs, doc(notable_trait))] #[doc(alias = "Parseable")] pubtrait Parsable: sealed::Sealed {} impl Parsable for BorrowedFormatItem<'_> {} impl Parsable for [BorrowedFormatItem<'_>] {} #[cfg(feature = "alloc")] impl Parsable for OwnedFormatItem {} #[cfg(feature = "alloc")] impl Parsable for [OwnedFormatItem] {} impl Parsable for Rfc2822 {} impl Parsable for Rfc3339 {} impl<const CONFIG: EncodedConfig> Parsable for Iso8601<CONFIG> {} impl<T: Deref> Parsable for T where T::Target: Parsable {}
/// Seal the trait to prevent downstream users from implementing it, while still allowing it to /// exist in generic bounds. mod sealed { #[allow(clippy::wildcard_imports)] usesuper::*; usecrate::PrimitiveDateTime;
/// Parse the item using a format description and an input. pubtrait Sealed { /// Parse the item into the provided [`Parsed`] struct. /// /// This method can be used to parse a single component without parsing the full value. fn parse_into<'a>(
&self,
input: &'a [u8],
parsed: &mut Parsed,
) -> Result<&'a [u8], error::Parse>;
/// Parse the item into a new [`Parsed`] struct. /// /// This method can only be used to parse a complete value of a type. If any characters /// remain after parsing, an error will be returned. fn parse(&self, input: &[u8]) -> Result<Parsed, error::Parse> { letmut parsed = Parsed::new(); ifself.parse_into(input, &mut parsed)?.is_empty() {
Ok(parsed)
} else {
Err(error::Parse::ParseFromDescription(
error::ParseFromDescription::UnexpectedTrailingCharacters,
))
}
}
/// Parse a [`Date`] from the format description. fn parse_date(&self, input: &[u8]) -> Result<Date, error::Parse> {
Ok(self.parse(input)?.try_into()?)
}
/// Parse a [`Time`] from the format description. fn parse_time(&self, input: &[u8]) -> Result<Time, error::Parse> {
Ok(self.parse(input)?.try_into()?)
}
/// Parse a [`UtcOffset`] from the format description. fn parse_offset(&self, input: &[u8]) -> Result<UtcOffset, error::Parse> {
Ok(self.parse(input)?.try_into()?)
}
/// Parse a [`PrimitiveDateTime`] from the format description. fn parse_primitive_date_time(
&self,
input: &[u8],
) -> Result<PrimitiveDateTime, error::Parse> {
Ok(self.parse(input)?.try_into()?)
}
/// Parse a [`OffsetDateTime`] from the format description. fn parse_offset_date_time(&self, input: &[u8]) -> Result<OffsetDateTime, error::Parse> {
Ok(self.parse(input)?.try_into()?)
}
}
}
let colon = ascii_char::<b':'>; let comma = ascii_char::<b','>;
let input = opt(cfws)(input).into_inner(); // This parses the weekday, but we don't actually use the value anywhere. Because of this, // just return `()` to avoid unnecessary generated code. let weekday = first_match(
[
(b"Mon".as_slice(), ()),
(b"Tue".as_slice(), ()),
(b"Wed".as_slice(), ()),
(b"Thu".as_slice(), ()),
(b"Fri".as_slice(), ()),
(b"Sat".as_slice(), ()),
(b"Sun".as_slice(), ()),
], false,
)(input); let input = iflet Some(item) = weekday { let input = item.into_inner(); let input = comma(input).ok_or(InvalidLiteral)?.into_inner();
opt(cfws)(input).into_inner()
} else {
input
}; let ParsedItem(input, day) =
n_to_m_digits::<1, 2, _>(input).ok_or(InvalidComponent("day"))?; let input = cfws(input).ok_or(InvalidLiteral)?.into_inner(); let ParsedItem(input, month) = first_match(
[
(b"Jan".as_slice(), Month::January),
(b"Feb".as_slice(), Month::February),
(b"Mar".as_slice(), Month::March),
(b"Apr".as_slice(), Month::April),
(b"May".as_slice(), Month::May),
(b"Jun".as_slice(), Month::June),
(b"Jul".as_slice(), Month::July),
(b"Aug".as_slice(), Month::August),
(b"Sep".as_slice(), Month::September),
(b"Oct".as_slice(), Month::October),
(b"Nov".as_slice(), Month::November),
(b"Dec".as_slice(), Month::December),
], false,
)(input)
.ok_or(InvalidComponent("month"))?; let input = cfws(input).ok_or(InvalidLiteral)?.into_inner(); let (input, year) = match exactly_n_digits::<4, u32>(input) {
Some(item) => { let ParsedItem(input, year) = item
.flat_map(|year| if year >= 1900 { Some(year) } else { None })
.ok_or(InvalidComponent("year"))?; let input = fws(input).ok_or(InvalidLiteral)?.into_inner();
(input, year)
}
None => { let ParsedItem(input, year) = exactly_n_digits::<2, u32>(input)
.map(|item| item.map(|year| if year < 50 { year + 2000 } else { year + 1900 }))
.ok_or(InvalidComponent("year"))?; let input = cfws(input).ok_or(InvalidLiteral)?.into_inner();
(input, year)
}
};
let ParsedItem(input, hour) =
exactly_n_digits::<2, _>(input).ok_or(InvalidComponent("hour"))?; let input = opt(cfws)(input).into_inner(); let input = colon(input).ok_or(InvalidLiteral)?.into_inner(); let input = opt(cfws)(input).into_inner(); let ParsedItem(input, minute) =
exactly_n_digits::<2, _>(input).ok_or(InvalidComponent("minute"))?;
let (input, mut second) = iflet Some(input) = colon(opt(cfws)(input).into_inner()) { let input = input.into_inner(); // discard the colon let input = opt(cfws)(input).into_inner(); let ParsedItem(input, second) =
exactly_n_digits::<2, _>(input).ok_or(InvalidComponent("second"))?; let input = cfws(input).ok_or(InvalidLiteral)?.into_inner();
(input, second)
} else {
(cfws(input).ok_or(InvalidLiteral)?.into_inner(), 0)
};
if !input.is_empty() { return Err(error::Parse::ParseFromDescription(
error::ParseFromDescription::UnexpectedTrailingCharacters,
));
}
letmut nanosecond = 0; let leap_second_input = if second == 60 {
second = 59;
nanosecond = 999_999_999; true
} else { false
};
let dt = (|| { let date = Date::from_calendar_date(year.cast_signed(), month, day)?; let time = Time::from_hms_nano(hour, minute, second, nanosecond)?; let offset = UtcOffset::from_hms(offset_hour, offset_minute, 0)?;
Ok(OffsetDateTime::new_in_offset(date, time, offset))
})()
.map_err(TryFromParsed::ComponentRange)?;
ParsedItem(input, value)
} else {
ParsedItem(input, 0)
}; let ParsedItem(input, offset) = { iflet Some(ParsedItem(input, ())) = ascii_char_ignore_case::<b'Z'>(input) {
ParsedItem(input, UtcOffset::UTC)
} else { let ParsedItem(input, offset_sign) =
sign(input).ok_or(InvalidComponent("offset hour"))?; let ParsedItem(input, offset_hour) = exactly_n_digits::<2, u8>(input)
.and_then(|parsed| parsed.filter(|&offset_hour| offset_hour <= 23))
.ok_or(InvalidComponent("offset hour"))?; let input = colon(input).ok_or(InvalidLiteral)?.into_inner(); let ParsedItem(input, offset_minute) =
exactly_n_digits::<2, u8>(input).ok_or(InvalidComponent("offset minute"))?;
UtcOffset::from_hms( if offset_sign == b'-' {
-offset_hour.cast_signed()
} else {
offset_hour.cast_signed()
}, if offset_sign == b'-' {
-offset_minute.cast_signed()
} else {
offset_minute.cast_signed()
}, 0,
)
.map(|offset| ParsedItem(input, offset))
.map_err(|mut err| { // Provide the user a more accurate error. if err.name == "hours" {
err.name = "offset hour";
} elseif err.name == "minutes" {
err.name = "offset minute";
}
err
})
.map_err(TryFromParsed::ComponentRange)?
}
};
if !input.is_empty() { return Err(error::Parse::ParseFromDescription(
error::ParseFromDescription::UnexpectedTrailingCharacters,
));
}
// The RFC explicitly permits leap seconds. We don't currently support them, so treat it as // the preceding nanosecond. However, leap seconds can only occur as the last second of the // month UTC. let leap_second_input = if second == 60 {
second = 59;
nanosecond = 999_999_999; true
} else { false
};
let date = Month::from_number(month)
.and_then(|month| Date::from_calendar_date(year.cast_signed(), month, day))
.map_err(TryFromParsed::ComponentRange)?; let time = Time::from_hms_nano(hour, minute, second, nanosecond)
.map_err(TryFromParsed::ComponentRange)?; let dt = OffsetDateTime::new_in_offset(date, time, offset);
// If a date and offset are present, a time must be as well. if !date_is_present || time_is_present { matchSelf::parse_offset(parsed, &mut extended_kind)(input) {
Ok(new_input) => {
input = new_input;
offset_is_present = true;
}
Err(err) => {
first_error.get_or_insert(err);
}
}
}
if !date_is_present && !time_is_present && !offset_is_present { match first_error {
Some(err) => return Err(err),
None => bug!("an error should be present if no components were parsed"),
}
}
Ok(input)
}
} // endregion well-known formats
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.14 Sekunden
(vorverarbeitet am 2026-06-18)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.