diff --git a/src/format/parse.rs b/src/format/parse.rs index 3f9fccd29b..4a731fd59d 100644 --- a/src/format/parse.rs +++ b/src/format/parse.rs @@ -542,7 +542,8 @@ impl str::FromStr for DateTime { /// Differences with RFC3339: /// - Values don't require padding to two digits. /// - Years outside the range 0...=9999 are accepted, but they must include a sign. -/// - `UTC` is accepted as a valid timezone name/offset. +/// - `UTC` is accepted as a valid timezone name/offset (for compatibility with the debug format of +/// `DateTime`. /// - There can be spaces between any of the components. /// - The colon in the offset may be missing. fn parse_rfc3339_relaxed<'a>(parsed: &mut Parsed, mut s: &'a str) -> ParseResult<(&'a str, ())> { @@ -565,7 +566,6 @@ fn parse_rfc3339_relaxed<'a>(parsed: &mut Parsed, mut s: &'a str) -> ParseResult Item::Numeric(Numeric::Second, Pad::Zero), Item::Fixed(Fixed::Nanosecond), Item::Space(""), - Item::Fixed(Fixed::TimezoneOffsetZ), ]; s = match parse_internal(parsed, s, DATE_ITEMS.iter()) { @@ -580,11 +580,19 @@ fn parse_rfc3339_relaxed<'a>(parsed: &mut Parsed, mut s: &'a str) -> ParseResult None => return Err(TOO_SHORT), }; - match parse_internal(parsed, s, TIME_ITEMS.iter()) { - Err((s, e)) if e.0 == ParseErrorKind::TooLong => Ok((s, ())), - Err((_s, e)) => Err(e), - Ok(s) => Ok((s, ())), - } + s = match parse_internal(parsed, s, TIME_ITEMS.iter()) { + Err((s, e)) if e.0 == ParseErrorKind::TooLong => s, + Err((_s, e)) => return Err(e), + Ok(_) => return Err(NOT_ENOUGH), + }; + s = s.trim_start(); + let (s, offset) = if s.starts_with("UTC") || s.starts_with("utc") { + (&s[3..], 0) + } else { + scan::timezone_offset(s, scan::colon_or_space, true, false, true)? + }; + parsed.set_offset(i64::from(offset))?; + Ok((s, ())) } #[cfg(test)] diff --git a/src/format/scan.rs b/src/format/scan.rs index 32ca2659f2..98f3673ff1 100644 --- a/src/format/scan.rs +++ b/src/format/scan.rs @@ -210,21 +210,8 @@ where F: FnMut(&str) -> ParseResult<&str>, { if allow_zulu { - let bytes = s.as_bytes(); - match bytes.first() { - Some(&b'z') | Some(&b'Z') => return Ok((&s[1..], 0)), - Some(&b'u') | Some(&b'U') => { - if bytes.len() >= 3 { - let (b, c) = (bytes[1], bytes[2]); - match (b | 32, c | 32) { - (b't', b'c') => return Ok((&s[3..], 0)), - _ => return Err(INVALID), - } - } else { - return Err(INVALID); - } - } - _ => {} + if let Some(&b'Z' | &b'z') = s.as_bytes().first() { + return Ok((&s[1..], 0)); } }