From af2da5ac10091b6c2ca96931efe5ceb8454aa771 Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Fri, 19 May 2023 16:24:07 +0200 Subject: [PATCH] Parse invalid single-letter timezones as `-00:00` --- src/format/parse.rs | 11 ++++++----- src/format/scan.rs | 27 +++++++++++++-------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/format/parse.rs b/src/format/parse.rs index 74bfaf768a..c4e2561500 100644 --- a/src/format/parse.rs +++ b/src/format/parse.rs @@ -1296,12 +1296,13 @@ mod tests { ("Tue, 20 Jan 2015 17:35:20 PDT", Ok("Tue, 20 Jan 2015 17:35:20 -0700")), ("Tue, 20 Jan 2015 17:35:20 PST", Ok("Tue, 20 Jan 2015 17:35:20 -0800")), ("Tue, 20 Jan 2015 17:35:20 pst", Ok("Tue, 20 Jan 2015 17:35:20 -0800")), - // named single-letter military timezones must fallback to +0000 + // Z is the only single-letter military timezones that maps to +0000 ("Tue, 20 Jan 2015 17:35:20 Z", Ok("Tue, 20 Jan 2015 17:35:20 +0000")), - ("Tue, 20 Jan 2015 17:35:20 A", Ok("Tue, 20 Jan 2015 17:35:20 +0000")), - ("Tue, 20 Jan 2015 17:35:20 a", Ok("Tue, 20 Jan 2015 17:35:20 +0000")), - ("Tue, 20 Jan 2015 17:35:20 K", Ok("Tue, 20 Jan 2015 17:35:20 +0000")), - ("Tue, 20 Jan 2015 17:35:20 k", Ok("Tue, 20 Jan 2015 17:35:20 +0000")), + // other named single-letter military timezones must fallback to -0000 + ("Tue, 20 Jan 2015 17:35:20 A", Ok("Tue, 20 Jan 2015 17:35:20 -0000")), + ("Tue, 20 Jan 2015 17:35:20 a", Ok("Tue, 20 Jan 2015 17:35:20 -0000")), + ("Tue, 20 Jan 2015 17:35:20 K", Ok("Tue, 20 Jan 2015 17:35:20 -0000")), + ("Tue, 20 Jan 2015 17:35:20 k", Ok("Tue, 20 Jan 2015 17:35:20 -0000")), // named single-letter timezone "J" is specifically not valid ("Tue, 20 Jan 2015 17:35:20 J", Err(INVALID)), ("Tue, 20 Jan 2015 17:35:20 -0890", Err(OUT_OF_RANGE)), // bad offset minutes diff --git a/src/format/scan.rs b/src/format/scan.rs index 659308e727..f923f3d21a 100644 --- a/src/format/scan.rs +++ b/src/format/scan.rs @@ -356,30 +356,29 @@ pub(super) fn timezone_offset_2822(s: &str) -> ParseResult<(&str, Option)> let name = &s.as_bytes()[..upto]; let s = &s[upto..]; let offset_hours = |o| Ok((s, Some(o * 3600))); - if equals(name, "gmt") || equals(name, "ut") { - offset_hours(0) + // RFC 2822 requires support for some named North America timezones, a small subset of all + // named timezones. + if equals(name, "gmt") || equals(name, "ut") || equals(name, "z") || equals(name, "Z") { + return offset_hours(0); } else if equals(name, "edt") { - offset_hours(-4) + return offset_hours(-4); } else if equals(name, "est") || equals(name, "cdt") { - offset_hours(-5) + return offset_hours(-5); } else if equals(name, "cst") || equals(name, "mdt") { - offset_hours(-6) + return offset_hours(-6); } else if equals(name, "mst") || equals(name, "pdt") { - offset_hours(-7) + return offset_hours(-7); } else if equals(name, "pst") { - offset_hours(-8) + return offset_hours(-8); } else if name.len() == 1 { - match name[0] { + if let b'a'..=b'i' | b'k'..=b'y' | b'A'..=b'I' | b'K'..=b'Y' = name[0] { // recommended by RFC 2822: consume but treat it as -0000 - b'a'..=b'i' | b'k'..=b'z' | b'A'..=b'I' | b'K'..=b'Z' => offset_hours(0), - _ => Err(INVALID), + return Ok((s, None)); } - } else { - Err(INVALID) } + Err(INVALID) } else { - let (s_, offset) = timezone_offset_internal(s, |s| Ok(s), false, false)?; - Ok((s_, offset)) + timezone_offset_internal(s, |s| Ok(s), false, false) } }