Skip to content

Commit 53ea528

Browse files
committed
Support parsing negative timestamps
1 parent 5304354 commit 53ea528

File tree

2 files changed

+14
-4
lines changed

2 files changed

+14
-4
lines changed

src/format/parse.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ where
357357
Minute => (2, false, Parsed::set_minute),
358358
Second => (2, false, Parsed::set_second),
359359
Nanosecond => (9, false, Parsed::set_nanosecond),
360-
Timestamp => (usize::MAX, false, Parsed::set_timestamp),
360+
Timestamp => (usize::MAX, true, Parsed::set_timestamp),
361361

362362
// for the future expansion
363363
Internal(ref int) => match int._dummy {},
@@ -366,8 +366,7 @@ where
366366
s = s.trim_start();
367367
let v = if signed {
368368
if s.starts_with('-') {
369-
let v = try_consume!(scan::number(&s[1..], 1, usize::MAX));
370-
0i64.checked_sub(v).ok_or(OUT_OF_RANGE)?
369+
try_consume!(scan::negative_number(&s[1..], 1, usize::MAX))
371370
} else if s.starts_with('+') {
372371
try_consume!(scan::number(&s[1..], 1, usize::MAX))
373372
} else {
@@ -765,6 +764,7 @@ mod tests {
765764
check(" + 42", &[Space(" "), num(Year)], Err(INVALID));
766765
check("-", &[num(Year)], Err(TOO_SHORT));
767766
check("+", &[num(Year)], Err(TOO_SHORT));
767+
check("-9223372036854775808", &[num(Timestamp)], parsed!(timestamp: i64::MIN));
768768

769769
// unsigned numeric
770770
check("345", &[num(Ordinal)], parsed!(ordinal: 345));

src/format/scan.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,16 @@ use crate::Weekday;
1515
/// Any number that does not fit in `i64` is an error.
1616
#[inline]
1717
pub(super) fn number(s: &str, min: usize, max: usize) -> ParseResult<(&str, i64)> {
18+
let (s, n) = negative_number(s, min, max)?;
19+
Ok((s, n.checked_neg().ok_or(OUT_OF_RANGE)?))
20+
}
21+
22+
/// Tries to parse a negative number from `min` to `max` digits.
23+
///
24+
/// This method parses a value as a negative integer, of wich the range is one larger than the range
25+
/// of positive integers. This is to allows us to parse `i64::MIN`.
26+
#[inline]
27+
pub(super) fn negative_number(s: &str, min: usize, max: usize) -> ParseResult<(&str, i64)> {
1828
assert!(min <= max);
1929

2030
// We are only interested in ascii numbers, so we can work with the `str` as bytes. We stop on
@@ -36,7 +46,7 @@ pub(super) fn number(s: &str, min: usize, max: usize) -> ParseResult<(&str, i64)
3646
}
3747
}
3848

39-
n = match n.checked_mul(10).and_then(|n| n.checked_add((c - b'0') as i64)) {
49+
n = match n.checked_mul(10).and_then(|n| n.checked_sub((c - b'0') as i64)) {
4050
Some(n) => n,
4151
None => return Err(OUT_OF_RANGE),
4252
};

0 commit comments

Comments
 (0)