diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index 14748444..0f673397 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -216,7 +216,7 @@ fn decode_bson(reader: &mut R, tag: u8, utf8_lossy: bool) -> D // The int64 is UTC milliseconds since the Unix epoch. let time = read_i64(reader)?; - match Utc.timestamp_opt(time / 1000, ((time % 1000) as u32).saturating_mul(1_000_000)) { + match Utc.timestamp_opt(time / 1000, ((time % 1000) as u32) * 1_000_000) { LocalResult::None => Err(DecoderError::InvalidTimestamp(time)), LocalResult::Ambiguous(..) => Err(DecoderError::AmbiguousTimestamp(time)), LocalResult::Single(t) => Ok(Bson::UtcDatetime(t)), diff --git a/src/encoder/mod.rs b/src/encoder/mod.rs index b9b88dc9..2e6adf57 100644 --- a/src/encoder/mod.rs +++ b/src/encoder/mod.rs @@ -138,10 +138,7 @@ fn encode_bson(writer: &mut W, key: &str, val: &Bson) -> Enco writer.write_u8(From::from(subtype))?; writer.write_all(data).map_err(From::from) } - &Bson::UtcDatetime(ref v) => { - write_i64(writer, - (v.timestamp() * 1000) + (v.nanosecond() / 1000000) as i64) - } + &Bson::UtcDatetime(ref v) => write_i64(writer, (v.timestamp() * 1000) + (v.nanosecond() / 1_000_000) as i64), &Bson::Null => Ok(()), &Bson::Symbol(ref v) => write_string(writer, &v), &Bson::Decimal128(ref v) => write_f128(writer, v.clone()), diff --git a/tests/lib.rs b/tests/lib.rs index eaa3c4d0..f3bdc21b 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -1,5 +1,6 @@ #[macro_use(bson, doc)] extern crate bson; +extern crate byteorder; extern crate chrono; <<<<<<< HEAD extern crate rustc_serialize; diff --git a/tests/modules/encoder_decoder.rs b/tests/modules/encoder_decoder.rs index 1c2d50c4..1176a608 100644 --- a/tests/modules/encoder_decoder.rs +++ b/tests/modules/encoder_decoder.rs @@ -1,10 +1,15 @@ -use bson::{decode_document, encode_document, Bson, decode_document_utf8_lossy}; use bson::oid::ObjectId; use bson::spec::BinarySubtype; +<<<<<<< HEAD use bson::decimal128::Decimal128; use chrono::Utc; +======= +use bson::{decode_document, decode_document_utf8_lossy, encode_document, Bson}; +use byteorder::{LittleEndian, WriteBytesExt}; +>>>>>>> [#64] Reverted saturating usec of UTC time use chrono::offset::TimeZone; -use std::io::Cursor; +use chrono::Utc; +use std::io::{Cursor, Write}; #[test] fn test_encode_decode_floating_point() { @@ -295,3 +300,21 @@ fn test_encode_decode_decimal128() { let decoded = decode_document(&mut Cursor::new(buf)).unwrap(); assert_eq!(decoded, doc); } + +#[test] +fn test_decode_utc_date_time_overflows() { + let t = 1530492218 * 1_000 + 999; + + let mut raw0 = vec![0x09, b'A', 0x00]; + raw0.write_i64::(t).unwrap(); + + let mut raw = vec![]; + raw.write_i32::((raw0.len() + 4 + 1) as i32).unwrap(); + raw.write_all(&raw0).unwrap(); + raw.write_u8(0).unwrap(); + + let decoded = decode_document(&mut Cursor::new(raw)).unwrap(); + + let expected = doc! { "A" => Utc.timestamp(1530492218, 999 * 1_000_000)}; + assert_eq!(decoded, expected); +}