Take exactly num digits specified for nanosecond fixed
Error if it's too long or short, and don't take any more digits
This commit is contained in:
parent
8a2b09962a
commit
937189ee52
|
@ -5,7 +5,6 @@
|
|||
//! Date and time parsing routines.
|
||||
|
||||
use std::usize;
|
||||
use std::cmp;
|
||||
|
||||
use Weekday;
|
||||
|
||||
|
@ -317,28 +316,22 @@ pub fn parse<'a, I>(parsed: &mut Parsed, mut s: &str, items: I) -> ParseResult<(
|
|||
}
|
||||
|
||||
Nanosecond3NoDot => {
|
||||
if !s.is_empty() {
|
||||
let max_index = cmp::min(s.len() as u64, 3) as usize;
|
||||
let nano = try_consume!(scan::nanosecond(&s[..max_index]));
|
||||
if s.len() < 3 { return Err(TOO_SHORT); }
|
||||
let nano = try_consume!(scan::nanosecond_fixed(s, 3));
|
||||
try!(parsed.set_nanosecond(nano));
|
||||
}
|
||||
}
|
||||
|
||||
Nanosecond6NoDot => {
|
||||
if !s.is_empty() {
|
||||
let max_index = cmp::min(s.len() as u64, 6) as usize;
|
||||
let nano = try_consume!(scan::nanosecond(&s[..max_index]));
|
||||
if s.len() < 6 { return Err(TOO_SHORT); }
|
||||
let nano = try_consume!(scan::nanosecond_fixed(s, 6));
|
||||
try!(parsed.set_nanosecond(nano));
|
||||
}
|
||||
}
|
||||
|
||||
Nanosecond9NoDot => {
|
||||
if !s.is_empty() {
|
||||
let max_index = cmp::min(s.len() as u64, 9) as usize;
|
||||
let nano = try_consume!(scan::nanosecond(&s[..max_index]));
|
||||
if s.len() < 9 { return Err(TOO_SHORT); }
|
||||
let nano = try_consume!(scan::nanosecond_fixed(s, 9));
|
||||
try!(parsed.set_nanosecond(nano));
|
||||
}
|
||||
}
|
||||
|
||||
TimezoneName => return Err(BAD_FORMAT),
|
||||
|
||||
|
@ -560,44 +553,37 @@ fn test_parse() {
|
|||
check!(" .4", [fix!(Nanosecond)]; TOO_LONG); // no automatic trimming
|
||||
|
||||
// fixed: nanoseconds without the dot
|
||||
check!("", [fix!(Nanosecond3NoDot)]; ); // no field set, but not an error
|
||||
check!("0", [fix!(Nanosecond3NoDot)]; nanosecond: 0);
|
||||
check!("4", [fix!(Nanosecond3NoDot)]; nanosecond: 400_000_000);
|
||||
check!("42", [fix!(Nanosecond3NoDot)]; nanosecond: 420_000_000);
|
||||
check!("", [fix!(Nanosecond3NoDot)]; TOO_SHORT);
|
||||
check!("0", [fix!(Nanosecond3NoDot)]; TOO_SHORT);
|
||||
check!("4", [fix!(Nanosecond3NoDot)]; TOO_SHORT);
|
||||
check!("42", [fix!(Nanosecond3NoDot)]; TOO_SHORT);
|
||||
check!("421", [fix!(Nanosecond3NoDot)]; nanosecond: 421_000_000);
|
||||
check!("42195", [fix!(Nanosecond3NoDot)]; nanosecond: 421_000_000); // ignores everything after 3 digits
|
||||
check!("000000000547", [fix!(Nanosecond3NoDot)]; nanosecond: 0);
|
||||
check!("4x", [fix!(Nanosecond3NoDot)]; TOO_LONG);
|
||||
check!("42143", [fix!(Nanosecond3NoDot), num!(Second)]; nanosecond: 421_000_000, second: 43);
|
||||
check!("42195", [fix!(Nanosecond3NoDot)]; TOO_LONG);
|
||||
check!("4x", [fix!(Nanosecond3NoDot)]; TOO_SHORT);
|
||||
check!(" 4", [fix!(Nanosecond3NoDot)]; INVALID);
|
||||
check!(".421", [fix!(Nanosecond3NoDot)]; INVALID);
|
||||
|
||||
check!("", [fix!(Nanosecond6NoDot)]; ); // no field set, but not an error
|
||||
check!("0", [fix!(Nanosecond6NoDot)]; nanosecond: 0);
|
||||
check!("4", [fix!(Nanosecond6NoDot)]; nanosecond: 400_000_000);
|
||||
check!("42", [fix!(Nanosecond6NoDot)]; nanosecond: 420_000_000);
|
||||
check!("421", [fix!(Nanosecond6NoDot)]; nanosecond: 421_000_000);
|
||||
check!("42195", [fix!(Nanosecond6NoDot)]; nanosecond: 421_950_000);
|
||||
check!("421950803", [fix!(Nanosecond6NoDot)]; nanosecond: 421_950_000); // ignores everything after 6 digits
|
||||
check!("000003547", [fix!(Nanosecond6NoDot)]; nanosecond: 3000);
|
||||
check!("000000547", [fix!(Nanosecond6NoDot)]; nanosecond: 0);
|
||||
check!("4x", [fix!(Nanosecond6NoDot)]; TOO_LONG);
|
||||
check!("", [fix!(Nanosecond6NoDot)]; TOO_SHORT);
|
||||
check!("0", [fix!(Nanosecond6NoDot)]; TOO_SHORT);
|
||||
check!("42195", [fix!(Nanosecond6NoDot)]; TOO_SHORT);
|
||||
check!("421950", [fix!(Nanosecond6NoDot)]; nanosecond: 421_950_000);
|
||||
check!("000003", [fix!(Nanosecond6NoDot)]; nanosecond: 3000);
|
||||
check!("000000", [fix!(Nanosecond6NoDot)]; nanosecond: 0);
|
||||
check!("4x", [fix!(Nanosecond6NoDot)]; TOO_SHORT);
|
||||
check!(" 4", [fix!(Nanosecond6NoDot)]; INVALID);
|
||||
check!(".421", [fix!(Nanosecond6NoDot)]; INVALID);
|
||||
check!(".42100", [fix!(Nanosecond6NoDot)]; INVALID);
|
||||
|
||||
check!("", [fix!(Nanosecond9NoDot)]; ); // no field set, but not an error
|
||||
check!("0", [fix!(Nanosecond9NoDot)]; nanosecond: 0);
|
||||
check!("4", [fix!(Nanosecond9NoDot)]; nanosecond: 400_000_000);
|
||||
check!("42", [fix!(Nanosecond9NoDot)]; nanosecond: 420_000_000);
|
||||
check!("421", [fix!(Nanosecond9NoDot)]; nanosecond: 421_000_000);
|
||||
check!("42195", [fix!(Nanosecond9NoDot)]; nanosecond: 421_950_000);
|
||||
check!("", [fix!(Nanosecond9NoDot)]; TOO_SHORT);
|
||||
check!("42195", [fix!(Nanosecond9NoDot)]; TOO_SHORT);
|
||||
check!("421950803", [fix!(Nanosecond9NoDot)]; nanosecond: 421_950_803);
|
||||
check!("421950803547", [fix!(Nanosecond9NoDot)]; nanosecond: 421_950_803);
|
||||
// check!("421950803547", [fix!(Nanosecond9NoDot), num!(Second)]; nanosecond: 421_950_803, second: 54); // don't skip digits that come after the 9
|
||||
check!("000000003547", [fix!(Nanosecond9NoDot)]; nanosecond: 3);
|
||||
check!("000000000547", [fix!(Nanosecond9NoDot)]; nanosecond: 0);
|
||||
check!("4x", [fix!(Nanosecond9NoDot)]; TOO_LONG);
|
||||
check!("000000003", [fix!(Nanosecond9NoDot)]; nanosecond: 3);
|
||||
check!("42195080354", [fix!(Nanosecond9NoDot), num!(Second)]; nanosecond: 421_950_803, second: 54); // don't skip digits that come after the 9
|
||||
check!("421950803547", [fix!(Nanosecond9NoDot)]; TOO_LONG);
|
||||
check!("000000000", [fix!(Nanosecond9NoDot)]; nanosecond: 0);
|
||||
check!("00000000x", [fix!(Nanosecond9NoDot)]; INVALID);
|
||||
check!(" 4", [fix!(Nanosecond9NoDot)]; INVALID);
|
||||
check!(".421", [fix!(Nanosecond9NoDot)]; INVALID);
|
||||
check!(".42100000", [fix!(Nanosecond9NoDot)]; INVALID);
|
||||
|
||||
// fixed: timezone offsets
|
||||
check!("+00:00", [fix!(TimezoneOffset)]; offset: 0);
|
||||
|
|
|
@ -66,6 +66,20 @@ pub fn nanosecond(s: &str) -> ParseResult<(&str, i64)> {
|
|||
Ok((s, v))
|
||||
}
|
||||
|
||||
/// Tries to consume a fixed number of digits as a fractional second.
|
||||
/// Returns the number of whole nanoseconds (0--999,999,999).
|
||||
pub fn nanosecond_fixed(s: &str, digits: usize) -> ParseResult<(&str, i64)> {
|
||||
// record the number of digits consumed for later scaling.
|
||||
let (s, v) = try!(number(s, digits, digits));
|
||||
|
||||
// scale the number accordingly.
|
||||
static SCALE: [i64; 10] = [0, 100_000_000, 10_000_000, 1_000_000, 100_000, 10_000,
|
||||
1_000, 100, 10, 1];
|
||||
let v = try!(v.checked_mul(SCALE[digits]).ok_or(OUT_OF_RANGE));
|
||||
|
||||
Ok((s, v))
|
||||
}
|
||||
|
||||
/// Tries to parse the month index (0 through 11) with the first three ASCII letters.
|
||||
pub fn short_month0(s: &str) -> ParseResult<(&str, u8)> {
|
||||
if s.len() < 3 { return Err(TOO_SHORT); }
|
||||
|
|
Loading…
Reference in New Issue