From 745a54c164233b3378ec54754f987b222dd10abe Mon Sep 17 00:00:00 2001 From: Simon Legner Date: Sun, 30 Jul 2023 12:12:59 +0200 Subject: [PATCH] Parse Zulu suffix with `%z` --- src/datetime/tests.rs | 12 ++++++++++++ src/format/parse.rs | 15 ++++++++------- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/datetime/tests.rs b/src/datetime/tests.rs index eeada41f03..a627592beb 100644 --- a/src/datetime/tests.rs +++ b/src/datetime/tests.rs @@ -942,6 +942,10 @@ fn test_utc_datetime_from_str() { "2015-02-18T23:16:9.15UTC".parse::>(), Ok(ymdhms_milli_utc(2015, 2, 18, 23, 16, 9, 150)) ); + assert_eq!( + DateTime::::parse_from_str("2015-02-18T23:16Z", "%Y-%m-%dT%H:%M%#z"), + Ok(ymdhms_milli_utc(2015, 2, 18, 23, 16, 0, 0)) + ); assert_eq!( "2015-2-18T23:16:9.15Z".parse::>(), @@ -1055,6 +1059,10 @@ fn test_datetime_parse_from_str() { assert_eq!(parse("Aug 09 2013 23:54:35 -0900::", "%b %d %Y %H:%M:%S %z::"), Ok(dt)); assert_eq!(parse("Aug 09 2013 23:54:35 -09:00:00", "%b %d %Y %H:%M:%S %z:00"), Ok(dt)); assert_eq!(parse("Aug 09 2013 23:54:35 -09:00:00 ", "%b %d %Y %H:%M:%S %z:00 "), Ok(dt)); + assert_eq!( + parse("2013-08-09T23:54:35Z", "%Y-%m-%dT%H:%M:%S%z"), + Ok(ymdhms(&FixedOffset::east_opt(0).unwrap(), 2013, 8, 9, 23, 54, 35)) + ); // // %:z @@ -1154,6 +1162,10 @@ fn test_datetime_parse_from_str() { assert!(parse("Aug 09 2013 -09:00:00 23:54:35", "%b %d %Y %#z %H:%M:%S").is_err()); // timezone data ambiguous with hours assert!(parse("Aug 09 2013 -09:00:23:54:35", "%b %d %Y %#z%H:%M:%S").is_err()); + assert_eq!( + parse("2013-08-09T23:54:35Z", "%Y-%m-%dT%H:%M:%S%#z"), + Ok(ymdhms(&FixedOffset::east_opt(0).unwrap(), 2013, 8, 9, 23, 54, 35)) + ); } #[test] diff --git a/src/format/parse.rs b/src/format/parse.rs index 7a9acda207..50d950ef11 100644 --- a/src/format/parse.rs +++ b/src/format/parse.rs @@ -480,10 +480,11 @@ where | &TimezoneOffsetTripleColon | &TimezoneOffset => { s = scan::trim1(s); + let allow_zulu = spec == &TimezoneOffset; let offset = try_consume!(scan::timezone_offset( s, scan::consume_colon_maybe, - false, + allow_zulu, false, true, )); @@ -1085,9 +1086,9 @@ mod tests { parsed!(offset: 45_240, day: 5), ); check("+12:34:", &[fixed(TimezoneOffset), Literal(":")], parsed!(offset: 45_240)); - check("Z12:34", &[fixed(TimezoneOffset)], Err(INVALID)); + check("Z12:34", &[fixed(TimezoneOffset)], Err(TOO_LONG)); check("X12:34", &[fixed(TimezoneOffset)], Err(INVALID)); - check("Z+12:34", &[fixed(TimezoneOffset)], Err(INVALID)); + check("Z+12:34", &[fixed(TimezoneOffset)], Err(TOO_LONG)); check("X+12:34", &[fixed(TimezoneOffset)], Err(INVALID)); check("X−12:34", &[fixed(TimezoneOffset)], Err(INVALID)); // MINUS SIGN (U+2212) check("🤠+12:34", &[fixed(TimezoneOffset)], Err(INVALID)); @@ -1100,7 +1101,7 @@ mod tests { check("-12:34🤠", &[fixed(TimezoneOffset), Literal("🤠")], parsed!(offset: -45_240)); check("−12:34🤠", &[fixed(TimezoneOffset), Literal("🤠")], parsed!(offset: -45_240)); // MINUS SIGN (U+2212) check("🤠+12:34", &[Literal("🤠"), fixed(TimezoneOffset)], parsed!(offset: 45_240)); - check("Z", &[fixed(TimezoneOffset)], Err(INVALID)); + check("Z", &[fixed(TimezoneOffset)], parsed!(offset: 0)); check("A", &[fixed(TimezoneOffset)], Err(INVALID)); check("PST", &[fixed(TimezoneOffset)], Err(INVALID)); check("#Z", &[fixed(TimezoneOffset)], Err(INVALID)); @@ -1108,10 +1109,10 @@ mod tests { check("+Z", &[fixed(TimezoneOffset)], Err(TOO_SHORT)); check("+:Z", &[fixed(TimezoneOffset)], Err(INVALID)); check("+Z:", &[fixed(TimezoneOffset)], Err(INVALID)); - check("z", &[fixed(TimezoneOffset)], Err(INVALID)); + check("z", &[fixed(TimezoneOffset)], parsed!(offset: 0)); check(" :Z", &[fixed(TimezoneOffset)], Err(INVALID)); - check(" Z", &[fixed(TimezoneOffset)], Err(INVALID)); - check(" z", &[fixed(TimezoneOffset)], Err(INVALID)); + check(" Z", &[fixed(TimezoneOffset)], parsed!(offset: 0)); + check(" z", &[fixed(TimezoneOffset)], parsed!(offset: 0)); // TimezoneOffsetColon check("1", &[fixed(TimezoneOffsetColon)], Err(INVALID));