diff --git a/src/parsers.rs b/src/parsers.rs index e8b58f05..552105e2 100644 --- a/src/parsers.rs +++ b/src/parsers.rs @@ -101,14 +101,6 @@ fn sign(i: &[u8]) -> IResult<&[u8], i32> { })(i) } -fn fractions(i: &[u8]) -> IResult<&[u8], f32> { - let (i, digits) = take_while(is_digit)(i)?; - let digits = str::from_utf8(digits).unwrap(); // This can't panic, `digits` will only include digits. - let f = format!("0.{}", digits).parse().unwrap(); // This can't panic, the string is a valid `f32`. - - Ok((i, f)) -} - // DATE // [+/-]YYYY @@ -204,8 +196,22 @@ fn time_second(i: &[u8]) -> IResult<&[u8], u32> { n_digit_in_range(i, 2, 0..=60) } -fn time_millisecond(fraction: f32) -> u32 { - (1000.0 * fraction) as u32 +fn time_millisecond(i: &[u8]) -> IResult<&[u8], u32> { + let (i, mut digits) = take_while(is_digit)(i)?; + let mut l = digits.len(); + if l > 3 { + digits = digits.get(0..3).unwrap(); + } + let mut result = 0; + if l > 0 { + let digits = str::from_utf8(digits).unwrap(); // This can't panic, `digits` will only include digits. + result = digits.parse().unwrap(); + } + while l < 3 { + result = result * 10; + l += 1; + } + Ok ((i,result)) } // HH:MM:[SS][.(m*)][(Z|+...|-...)] @@ -216,7 +222,7 @@ pub fn parse_time(i: &[u8]) -> IResult<&[u8], Time> { opt(tag(b":")), // : time_minute, // MM opt(preceded(opt(tag(b":")), time_second)), // [SS] - opt(map(preceded(one_of(",."), fractions), time_millisecond)), // [.(m*)] + opt(preceded(one_of(",."), time_millisecond)), // [.(m*)] opt(alt((timezone_hour, timezone_utc))), // [(Z|+...|-...)] )), |(h, _, m, s, ms, z)| { @@ -288,13 +294,27 @@ fn duration_minute(i: &[u8]) -> IResult<&[u8], u32> { // S[S][[,.][MS]] fn duration_second_and_millisecond(i: &[u8]) -> IResult<&[u8], (u32, u32)> { let (i, s) = m_to_n_digit_in_range(i, 1, 2, 0..=60)?; - let (i, ms) = opt(map(preceded(one_of(",."), fractions), duration_millisecond))(i)?; + let (i, ms) = opt(preceded(one_of(",."), duration_millisecond))(i)?; Ok((i, (s, ms.unwrap_or(0)))) } -fn duration_millisecond(fraction: f32) -> u32 { - (1000.0 * fraction) as u32 +fn duration_millisecond(i: &[u8]) -> IResult<&[u8], u32> { + let (i, mut digits) = take_while(is_digit)(i)?; + let mut l = digits.len(); + if l > 3 { + digits = digits.get(0..3).unwrap(); + } + let mut result = 0; + if l > 0 { + let digits = str::from_utf8(digits).unwrap(); // This can't panic, `digits` will only include digits. + result = digits.parse().unwrap(); + } + while l < 3 { + result = result * 10; + l += 1; + } + Ok ((i,result)) } fn duration_time(i: &[u8]) -> IResult<&[u8], (u32, u32, u32, u32)> { diff --git a/tests/lib.rs b/tests/lib.rs index 03b3a264..efe15a17 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -22,6 +22,22 @@ fn test_date() { #[test] fn test_millisecond() { + let mut i=0; + while i < 1000 { + //regression test for pull request 36. + assert_eq!( + Ok(Time { + hour: 16, + minute: 43, + second: 0, + millisecond: i, + tz_offset_hours: 0, + tz_offset_minutes: 0 + }), + time(format!("16:43:00.{:0>3}",i).as_str()) + ); + i+=1; + } assert_eq!( Ok(Time { hour: 16,