Skip to content

Commit 1eba93e

Browse files
authored
RUST-811 Improve ergonomics of bson::DateTime (#258)
This commit also fixes RUST-799 and RUST-825.
1 parent 0d373bf commit 1eba93e

File tree

19 files changed

+582
-299
lines changed

19 files changed

+582
-299
lines changed

.evergreen/run-tests.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ set -o errexit
44

55
. ~/.cargo/env
66
RUST_BACKTRACE=1 cargo test
7+
RUST_BACKTRACE=1 cargo test --features chrono-0_4,uuid-0_8

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ exclude = [
3333
[features]
3434
# no features by default
3535
default = []
36+
# if enabled, include API for interfacing with chrono 0.4
37+
chrono-0_4 = []
38+
# if enabled, include API for interfacing with uuid 0.8
39+
uuid-0_8 = []
3640
# attempt to encode unsigned types in signed types
3741
u2i = []
3842
# Decimal128 in BSON 1.1

examples/serialize.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
use std::io::Cursor;
22

3-
use bson::{oid, Bson, Document};
3+
use bson::{oid, Bson, DateTime, Document};
44

55
fn main() {
66
let mut doc = Document::new();
77
doc.insert("foo".to_string(), Bson::String("bar".to_string()));
88

99
let arr = vec![
1010
Bson::String("blah".to_string()),
11-
Bson::DateTime(chrono::Utc::now().into()),
11+
Bson::DateTime(DateTime::now()),
1212
Bson::ObjectId(oid::ObjectId::from_bytes([
1313
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
1414
])),

src/bson.rs

Lines changed: 17 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
2424
use std::fmt::{self, Debug, Display};
2525

26-
use chrono::{Datelike, NaiveDateTime, SecondsFormat, TimeZone, Utc};
26+
use chrono::Datelike;
2727
use serde_json::{json, Value};
2828

2929
pub use crate::document::Document;
@@ -285,9 +285,16 @@ impl From<oid::ObjectId> for Bson {
285285
}
286286
}
287287

288-
impl From<chrono::DateTime<Utc>> for Bson {
289-
fn from(a: chrono::DateTime<Utc>) -> Bson {
290-
Bson::DateTime(DateTime::from(a))
288+
#[cfg(feature = "chrono-0_4")]
289+
impl<T: chrono::TimeZone> From<chrono::DateTime<T>> for Bson {
290+
fn from(a: chrono::DateTime<T>) -> Bson {
291+
Bson::DateTime(crate::DateTime::from(a))
292+
}
293+
}
294+
295+
impl From<crate::DateTime> for Bson {
296+
fn from(dt: crate::DateTime) -> Self {
297+
Bson::DateTime(dt)
291298
}
292299
}
293300

@@ -370,15 +377,9 @@ impl Bson {
370377
})
371378
}
372379
Bson::ObjectId(v) => json!({"$oid": v.to_hex()}),
373-
Bson::DateTime(v) if v.timestamp_millis() >= 0 && v.0.year() <= 99999 => {
374-
let seconds_format = if v.0.timestamp_subsec_millis() == 0 {
375-
SecondsFormat::Secs
376-
} else {
377-
SecondsFormat::Millis
378-
};
379-
380+
Bson::DateTime(v) if v.timestamp_millis() >= 0 && v.to_chrono().year() <= 99999 => {
380381
json!({
381-
"$date": v.0.to_rfc3339_opts(seconds_format, true),
382+
"$date": v.to_rfc3339(),
382383
})
383384
}
384385
Bson::DateTime(v) => json!({
@@ -536,15 +537,9 @@ impl Bson {
536537
"$oid": v.to_string(),
537538
}
538539
}
539-
Bson::DateTime(v) if v.timestamp_millis() >= 0 && v.0.year() <= 99999 => {
540-
let seconds_format = if v.0.timestamp_subsec_millis() == 0 {
541-
SecondsFormat::Secs
542-
} else {
543-
SecondsFormat::Millis
544-
};
545-
540+
Bson::DateTime(v) if v.timestamp_millis() >= 0 && v.to_chrono().year() <= 99999 => {
546541
doc! {
547-
"$date": v.0.to_rfc3339_opts(seconds_format, true),
542+
"$date": v.to_rfc3339(),
548543
}
549544
}
550545
Bson::DateTime(v) => doc! {
@@ -735,12 +730,12 @@ impl Bson {
735730

736731
["$date"] => {
737732
if let Ok(date) = doc.get_i64("$date") {
738-
return Bson::DateTime(DateTime::from_millis(date));
733+
return Bson::DateTime(crate::DateTime::from_millis(date));
739734
}
740735

741736
if let Ok(date) = doc.get_str("$date") {
742737
if let Ok(date) = chrono::DateTime::parse_from_rfc3339(date) {
743-
return Bson::DateTime(date.with_timezone(&Utc).into());
738+
return Bson::DateTime(crate::DateTime::from_chrono(date));
744739
}
745740
}
746741
}
@@ -970,80 +965,6 @@ impl Timestamp {
970965
}
971966
}
972967

973-
/// Struct representing a BSON datetime.
974-
///
975-
/// Is is recommended to use a [`chrono::DateTime`] for date operations
976-
/// and to convert it to/from a [`crate::DateTime`] via the `From`/`Into` implementations.
977-
///
978-
/// ```
979-
/// use chrono::prelude::*;
980-
/// # fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
981-
/// let chrono_dt: chrono::DateTime<Utc> = "2014-11-28T12:00:09Z".parse()?;
982-
/// let bson_dt: bson::DateTime = chrono_dt.into();
983-
/// let back_to_chrono: chrono::DateTime<Utc> = bson_dt.into();
984-
/// # Ok(())
985-
/// # }
986-
/// ```
987-
///
988-
/// This type differs from [`chrono::DateTime`] in that it serializes to and deserializes from a
989-
/// BSON datetime rather than an ISO-8601 formatted string. This means that in non-BSON formats, it
990-
/// will serialize to and deserialize from that format's equivalent of the [extended JSON representation](https://docs.mongodb.com/manual/reference/mongodb-extended-json/) of a datetime. To serialize a
991-
/// [`chrono::DateTime`] as a BSON datetime, you can use
992-
/// [`serde_helpers::chrono_0_4_datetime_as_bson_datetime`].
993-
///
994-
/// ```rust
995-
/// use serde::{Serialize, Deserialize};
996-
///
997-
/// #[derive(Serialize, Deserialize)]
998-
/// struct Foo {
999-
/// // serializes as a BSON datetime.
1000-
/// date_time: bson::DateTime,
1001-
///
1002-
/// // serializes as an ISO-8601 string.
1003-
/// chrono_datetime: chrono::DateTime<chrono::Utc>,
1004-
///
1005-
/// // serializes as a BSON datetime.
1006-
/// #[serde(with = "bson::serde_helpers::chrono_0_4_datetime_as_bson_datetime")]
1007-
/// chrono_as_bson: chrono::DateTime<chrono::Utc>,
1008-
/// }
1009-
/// ```
1010-
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Copy, Clone)]
1011-
pub struct DateTime(chrono::DateTime<Utc>);
1012-
1013-
impl crate::DateTime {
1014-
pub(crate) fn from_millis(date: i64) -> Self {
1015-
Utc.timestamp_millis(date).into()
1016-
}
1017-
1018-
/// Returns the number of non-leap-milliseconds since January 1, 1970 UTC.
1019-
pub fn timestamp_millis(&self) -> i64 {
1020-
self.0.timestamp_millis()
1021-
}
1022-
}
1023-
1024-
impl Display for crate::DateTime {
1025-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1026-
Display::fmt(&self.0, f)
1027-
}
1028-
}
1029-
1030-
impl From<crate::DateTime> for chrono::DateTime<Utc> {
1031-
fn from(utc: DateTime) -> Self {
1032-
utc.0
1033-
}
1034-
}
1035-
1036-
impl<T: chrono::TimeZone> From<chrono::DateTime<T>> for crate::DateTime {
1037-
fn from(x: chrono::DateTime<T>) -> Self {
1038-
let dt = x.with_timezone(&Utc);
1039-
1040-
DateTime(chrono::DateTime::<Utc>::from_utc(
1041-
NaiveDateTime::from_timestamp(dt.timestamp(), dt.timestamp_subsec_millis() * 1_000_000),
1042-
Utc,
1043-
))
1044-
}
1045-
}
1046-
1047968
/// Represents a BSON regular expression value.
1048969
#[derive(Debug, Clone, PartialEq)]
1049970
pub struct Regex {

0 commit comments

Comments
 (0)