Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove partial support for handling -0000 offset #1411

Merged
merged 3 commits into from
Feb 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 11 additions & 10 deletions src/format/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,7 @@ fn parse_rfc2822<'a>(parsed: &mut Parsed, mut s: &'a str) -> ParseResult<(&'a st
}

s = scan::space(s)?; // mandatory
if let Some(offset) = try_consume!(scan::timezone_offset_2822(s)) {
// only set the offset when it is definitely known (i.e. not `-0000`)
parsed.set_offset(i64::from(offset))?;
}
parsed.set_offset(i64::from(try_consume!(scan::timezone_offset_2822(s))))?;

// optional comments
while let Ok((s_out, ())) = scan::comment_2822(s) {
Expand Down Expand Up @@ -216,7 +213,12 @@ pub(crate) fn parse_rfc3339<'a>(parsed: &mut Parsed, mut s: &'a str) -> ParseRes
}

let offset = try_consume!(scan::timezone_offset(s, |s| scan::char(s, b':'), true, false, true));
if offset <= -86_400 || offset >= 86_400 {
// This range check is similar to the one in `FixedOffset::east_opt`, so it would be redundant.
// But it is possible to read the offset directly from `Parsed`. We want to only successfully
// populate `Parsed` if the input is fully valid RFC 3339.
// Max for the hours field is `23`, and for the minutes field `59`.
const MAX_RFC3339_OFFSET: i32 = (23 * 60 + 59) * 60;
if !(-MAX_RFC3339_OFFSET..=MAX_RFC3339_OFFSET).contains(&offset) {
return Err(OUT_OF_RANGE);
}
parsed.set_offset(i64::from(offset))?;
Expand Down Expand Up @@ -1639,7 +1641,6 @@ mod tests {
("Tue, 20 Jan 2015 17:35:90 -0800", Err(OUT_OF_RANGE)), // bad second
("Tue, 20 Jan 2015 17:35:20 -0890", Err(OUT_OF_RANGE)), // bad offset
("6 Jun 1944 04:00:00Z", Err(INVALID)), // bad offset (zulu not allowed)
("Tue, 20 Jan 2015 17:35:20 HAS", Err(NOT_ENOUGH)), // bad named time zone
// named timezones that have specific timezone offsets
// see https://www.rfc-editor.org/rfc/rfc2822#section-4.3
("Tue, 20 Jan 2015 17:35:20 GMT", Ok(ymd_hmsn(2015, 1, 20, 17, 35, 20, 0, 0))),
Expand All @@ -1661,14 +1662,14 @@ mod tests {
("Tue, 20 Jan 2015 17:35:20 K", 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))),
// named single-letter timezone "J" is specifically not valid
("Tue, 20 Jan 2015 17:35:20 J", Err(NOT_ENOUGH)),
("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
("Tue, 20 Jan 2015 17:35:20Z", Err(INVALID)), // bad offset: zulu not allowed
("Tue, 20 Jan 2015 17:35:20 Zulu", Err(NOT_ENOUGH)), // bad offset: zulu not allowed
("Tue, 20 Jan 2015 17:35:20 ZULU", Err(NOT_ENOUGH)), // bad offset: zulu not allowed
("Tue, 20 Jan 2015 17:35:20 Zulu", Err(INVALID)), // bad offset: zulu not allowed
("Tue, 20 Jan 2015 17:35:20 ZULU", Err(INVALID)), // bad offset: zulu not allowed
("Tue, 20 Jan 2015 17:35:20 −0800", Err(INVALID)), // bad offset: timezone offset using MINUS SIGN (U+2212), not specified for RFC 2822
("Tue, 20 Jan 2015 17:35:20 0800", Err(INVALID)), // missing offset sign
("Tue, 20 Jan 2015 17:35:20 HAS", Err(NOT_ENOUGH)), // bad named timezone
("Tue, 20 Jan 2015 17:35:20 HAS", Err(INVALID)), // bad named timezone
("Tue, 20 Jan 2015😈17:35:20 -0800", Err(INVALID)), // bad character!
];

Expand Down
44 changes: 23 additions & 21 deletions src/format/scan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -287,37 +287,39 @@ where
/// See [RFC 2822 Section 4.3].
///
/// [RFC 2822 Section 4.3]: https://tools.ietf.org/html/rfc2822#section-4.3
pub(super) fn timezone_offset_2822(s: &str) -> ParseResult<(&str, Option<i32>)> {
pub(super) fn timezone_offset_2822(s: &str) -> ParseResult<(&str, i32)> {
// tries to parse legacy time zone names
let upto = s.as_bytes().iter().position(|&c| !c.is_ascii_alphabetic()).unwrap_or(s.len());
if upto > 0 {
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)
let offset_hours = |o| Ok((s, o * 3600));
// 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),
_ => Ok((s, None)),
return Ok((s, 0));
}
} else {
Ok((s, None))
}
Err(INVALID)
} else {
let (s_, offset) = timezone_offset(s, |s| Ok(s), false, false, false)?;
Ok((s_, Some(offset)))
timezone_offset(s, |s| Ok(s), false, false, false)
}
}

Expand Down Expand Up @@ -396,11 +398,11 @@ mod tests {

#[test]
fn test_timezone_offset_2822() {
assert_eq!(timezone_offset_2822("cSt").unwrap(), ("", Some(-21600)));
assert_eq!(timezone_offset_2822("pSt").unwrap(), ("", Some(-28800)));
assert_eq!(timezone_offset_2822("mSt").unwrap(), ("", Some(-25200)));
assert_eq!(timezone_offset_2822("-1551").unwrap(), ("", Some(-57060)));
assert_eq!(timezone_offset_2822("Gp").unwrap(), ("", None));
assert_eq!(timezone_offset_2822("cSt").unwrap(), ("", -21600));
assert_eq!(timezone_offset_2822("pSt").unwrap(), ("", -28800));
assert_eq!(timezone_offset_2822("mSt").unwrap(), ("", -25200));
assert_eq!(timezone_offset_2822("-1551").unwrap(), ("", -57060));
assert_eq!(timezone_offset_2822("Gp"), Err(INVALID));
}

#[test]
Expand Down
Loading