99//! * relative time to now, e.g. "+1 hour"
1010//!
1111use regex:: Error as RegexError ;
12+ use regex:: Regex ;
1213use std:: error:: Error ;
1314use std:: fmt:: { self , Display } ;
1415
@@ -75,6 +76,7 @@ mod format {
7576 pub const YYYYMMDDHHMMS_T_SEP : & str = "%Y-%m-%dT%H:%M:%S" ;
7677 pub const UTC_OFFSET : & str = "UTC%#z" ;
7778 pub const ZULU_OFFSET : & str = "Z%#z" ;
79+ pub const NAKED_OFFSET : & str = "%#z" ;
7880}
7981
8082/// Parses a time string and returns a `DateTime` representing the
@@ -219,8 +221,21 @@ pub fn parse_datetime_at_date<S: AsRef<str> + Clone>(
219221 // offsets, so instead we replicate parse_date behaviour by getting
220222 // the current date with local, and create a date time string at midnight,
221223 // before trying offset suffixes
222- let ts = format ! ( "{}" , date. format( "%Y%m%d" ) ) + "0000" + s. as_ref ( ) ;
223- for fmt in [ format:: UTC_OFFSET , format:: ZULU_OFFSET ] {
224+ //
225+ // HACK: if the string ends with a single digit preceded by a + or -
226+ // sign, then insert a 0 between the sign and the digit to make it
227+ // possible for `chrono` to parse it.
228+ let pattern = Regex :: new ( r"([\+-])(\d)$" ) . unwrap ( ) ;
229+ let ts = format ! (
230+ "{}0000{}" ,
231+ date. format( "%Y%m%d" ) ,
232+ pattern. replace( s. as_ref( ) , "${1}0${2}" )
233+ ) ;
234+ for fmt in [
235+ format:: UTC_OFFSET ,
236+ format:: ZULU_OFFSET ,
237+ format:: NAKED_OFFSET ,
238+ ] {
224239 let f = format:: YYYYMMDDHHMM . to_owned ( ) + fmt;
225240 if let Ok ( parsed) = DateTime :: parse_from_str ( & ts, & f) {
226241 return Ok ( parsed) ;
@@ -356,6 +371,8 @@ mod tests {
356371 "Z+07:00" ,
357372 "Z+0700" ,
358373 "Z+07" ,
374+ "+07" ,
375+ "+7" ,
359376 ] ;
360377
361378 let expected = format ! ( "{}{}" , Local :: now( ) . format( "%Y%m%d" ) , "0000+0700" ) ;
@@ -377,13 +394,11 @@ mod tests {
377394
378395 #[ test]
379396 fn invalid_offset_format ( ) {
380- let invalid_offsets = vec ! [ "+0700" , "UTC+2" , "Z-1" , "UTC+01005" ] ;
381- for offset in invalid_offsets {
382- assert_eq ! (
383- parse_datetime( offset) ,
384- Err ( ParseDateTimeError :: InvalidInput )
385- ) ;
386- }
397+ let offset = "UTC+01005" ;
398+ assert_eq ! (
399+ parse_datetime( offset) ,
400+ Err ( ParseDateTimeError :: InvalidInput )
401+ ) ;
387402 }
388403 }
389404
0 commit comments