// NOTE: critical field on time zones is captured but not handled.
// ==== Time Zone Annotation Parsing ====
/// We support two kinds of annotations here: annotations (e.g. `[u-ca=foo]`) /// and "time zone annotations" (`[UTC]` or `[+05:30]`) /// /// When parsing bracketed contents, we need to figure out which one we're dealing with. /// /// This function returns a time zone annotation if we are dealing with a time zone, /// otherwise it returns None (and the caller must handle non-tz annotations). pub(crate) fn parse_ambiguous_tz_annotation<'a, T: EncodingType>(
cursor: &mut Cursor<'a, T>,
) -> ParserResult<Option<TimeZoneAnnotation<'a, T>>> { // Peek position + 1 to check for critical flag. letmut current_peek = 1; let critical = cursor
.peek_n(current_peek)?
.map(is_critical_flag)
.ok_or(ParseError::abrupt_end("AmbiguousAnnotation"))?;
// Advance cursor if critical flag present. if critical {
current_peek += 1;
}
let leading_char = cursor
.peek_n(current_peek)?
.ok_or(ParseError::abrupt_end("AmbiguousAnnotation"))?;
// Ambigious start values when lowercase alpha that is shared between `TzLeadingChar` and `KeyLeadingChar`. if is_a_key_leading_char(leading_char) { letmut peek_pos = current_peek + 1; // Go through looking for `=` whilelet Some(ch) = cursor.peek_n(peek_pos)? { if is_annotation_key_value_separator(ch) { // We have an `=` sign, this is a non-tz annotation return Ok(None);
} elseif is_annotation_close(ch) { // We found a `]` without an `=`, this is a time zone let tz = parse_tz_annotation(cursor)?; return Ok(Some(tz));
}
peek_pos += 1;
}
Err(ParseError::abrupt_end("AmbiguousAnnotation"))
} else { // Unambiguously not a non-tz annotation, try parsing a tz annotation let tz = parse_tz_annotation(cursor)?;
Ok(Some(tz))
}
}
/// Parses a potentially full precision UTC offset or Z pub(crate) fn parse_date_time_utc_offset<T: EncodingType>(
cursor: &mut Cursor<T>,
) -> ParserResult<UtcOffsetRecordOrZ> { if cursor.check_or(false, is_utc_designator)? {
cursor.advance(); return Ok(UtcOffsetRecordOrZ::Z);
}
let utc_offset = parse_utc_offset(cursor)?;
Ok(UtcOffsetRecordOrZ::Offset(utc_offset))
}
/// Parse a potentially full precision `UtcOffset` pub(crate) fn parse_utc_offset<T: EncodingType>(
cursor: &mut Cursor<T>,
) -> ParserResult<UtcOffsetRecord> { let (minute_precision_offset, separated) = parse_utc_offset_minute_precision(cursor)?;
// If `UtcOffsetWithSubMinuteComponents`, continue parsing. if !cursor.check_or(false, |ch| ch.is_ascii_digit() || is_time_separator(ch))? { return Ok(UtcOffsetRecord::MinutePrecision(minute_precision_offset));
}
if Some(separated) != cursor.check(is_time_separator)? { return Err(ParseError::UtcTimeSeparator);
}
cursor.advance_if(cursor.check_or(false, is_time_separator)?);
/// Parse an `UtcOffsetMinutePrecision` node /// /// Returns the offset and whether the utc parsing includes a minute separator. pub(crate) fn parse_utc_offset_minute_precision<T: EncodingType>(
cursor: &mut Cursor<T>,
) -> ParserResult<(MinutePrecisionOffset, bool)> { // https://www.rfc-editor.org/rfc/rfc3339#section-5.6 let sign = cursor.next_or(ParseError::abrupt_end("time-numoffset"))?; if !is_ascii_sign(sign) { return Err(ParseError::OffsetNeedsSign);
} let sign = Sign::from(sign == b'+');
let hour = parse_hour(cursor)?;
// If at the end of the utc, then return. if !cursor.check_or(false, |ch| ch.is_ascii_digit() || is_time_separator(ch))? { let offset = MinutePrecisionOffset {
sign,
hour,
minute: 0,
}; return Ok((offset, false));
} // Advance cursor beyond any TimeSeparator let separated = cursor.check_or(false, is_time_separator)?;
cursor.advance_if(separated);
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.