Skip to content

Commit

Permalink
Parse invalid single-letter timezones as -00:00
Browse files Browse the repository at this point in the history
  • Loading branch information
pitdicker committed Jul 27, 2023
1 parent c564170 commit bdd511e
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 15 deletions.
19 changes: 18 additions & 1 deletion src/format/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1628,8 +1628,9 @@ mod tests {
("Tue, 20 Jan 2015 17:35:20 PDT", Ok(ymd_hmsn(2015, 1, 20, 17, 35, 20, 0, -7))),
("Tue, 20 Jan 2015 17:35:20 PST", Ok(ymd_hmsn(2015, 1, 20, 17, 35, 20, 0, -8))),
("Tue, 20 Jan 2015 17:35:20 pst", Ok(ymd_hmsn(2015, 1, 20, 17, 35, 20, 0, -8))),
// 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(ymd_hmsn(2015, 1, 20, 17, 35, 20, 0, 0))),
// named single-letter military timezones must fallback to +0000
("Tue, 20 Jan 2015 17:35:20 A", Ok(ymd_hmsn(2015, 1, 20, 17, 35, 20, 0, 0))),
("Tue, 20 Jan 2015 17:35:20 a", Ok(ymd_hmsn(2015, 1, 20, 17, 35, 20, 0, 0))),
("Tue, 20 Jan 2015 17:35:20 K", Ok(ymd_hmsn(2015, 1, 20, 17, 35, 20, 0, 0))),
Expand Down Expand Up @@ -1666,6 +1667,22 @@ mod tests {
}
}

#[test]
fn test_rfc2822_no_offset_info() {
fn rfc2822_to_offset(date: &str) -> FixedOffset {
let mut parsed = Parsed::new();
parse(&mut parsed, date, [Item::Fixed(Fixed::RFC2822)].iter()).unwrap();
parsed.to_fixed_offset().unwrap()
}
assert_eq!(
rfc2822_to_offset("Tue, 20 Jan 2015 17:35:20 -0000"),
FixedOffset::OFFSET_UNKNOWN
);
assert_eq!(rfc2822_to_offset("Tue, 20 Jan 2015 17:35:20 A"), FixedOffset::OFFSET_UNKNOWN);
assert_eq!(rfc2822_to_offset("Tue, 20 Jan 2015 17:35:20 a"), FixedOffset::OFFSET_UNKNOWN);
assert_eq!(rfc2822_to_offset("Tue, 20 Jan 2015 17:35:20 K"), FixedOffset::OFFSET_UNKNOWN);
}

#[test]
fn parse_rfc850() {
static RFC850_FMT: &str = "%A, %d-%b-%y %T GMT";
Expand Down
30 changes: 16 additions & 14 deletions src/format/scan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,30 +313,32 @@ pub(super) fn timezone_offset_2822(s: &str) -> ParseResult<(&str, Option<i32>)>
let name = &s.as_bytes()[..upto];
let s = &s[upto..];
let offset_hours = |o| Ok((s, Some(o * 3600)));
if name.eq_ignore_ascii_case(b"gmt") || name.eq_ignore_ascii_case(b"ut") {
offset_hours(0)
// RFC 2822 requires support for some named North America timezones, a small subset of all
// named timezones.
if name.eq_ignore_ascii_case(b"gmt")
|| name.eq_ignore_ascii_case(b"ut")
|| name.eq_ignore_ascii_case(b"z")
{
return offset_hours(0);
} else if name.eq_ignore_ascii_case(b"edt") {
offset_hours(-4)
return offset_hours(-4);
} else if name.eq_ignore_ascii_case(b"est") || name.eq_ignore_ascii_case(b"cdt") {
offset_hours(-5)
return offset_hours(-5);
} else if name.eq_ignore_ascii_case(b"cst") || name.eq_ignore_ascii_case(b"mdt") {
offset_hours(-6)
return offset_hours(-6);
} else if name.eq_ignore_ascii_case(b"mst") || name.eq_ignore_ascii_case(b"pdt") {
offset_hours(-7)
return offset_hours(-7);
} else if name.eq_ignore_ascii_case(b"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(s, |s| Ok(s), false, false, false)?;
Ok((s_, offset))
timezone_offset(s, |s| Ok(s), false, false, false)
}
}

Expand Down

0 comments on commit bdd511e

Please sign in to comment.