2121
2222//! BSON definition
2323
24- use std:: {
25- fmt:: { self , Debug , Display } ,
26- ops:: { Deref , DerefMut } ,
27- } ;
24+ use std:: fmt:: { self , Debug , Display } ;
2825
2926use chrono:: { Datelike , SecondsFormat , TimeZone , Utc } ;
3027use serde_json:: { json, Value } ;
@@ -68,7 +65,7 @@ pub enum Bson {
6865 /// [ObjectId](http://dochub.mongodb.org/core/objectids)
6966 ObjectId ( oid:: ObjectId ) ,
7067 /// UTC datetime
71- DateTime ( chrono :: DateTime < Utc > ) ,
68+ DateTime ( crate :: DateTime ) ,
7269 /// Symbol (Deprecated)
7370 Symbol ( String ) ,
7471 /// [128-bit decimal floating point](https://github.com/mongodb/specifications/blob/master/source/bson-decimal128/decimal128.rst)
@@ -290,7 +287,7 @@ impl From<oid::ObjectId> for Bson {
290287
291288impl From < chrono:: DateTime < Utc > > for Bson {
292289 fn from ( a : chrono:: DateTime < Utc > ) -> Bson {
293- Bson :: DateTime ( a )
290+ Bson :: DateTime ( DateTime ( a ) )
294291 }
295292}
296293
@@ -373,15 +370,15 @@ impl Bson {
373370 } )
374371 }
375372 Bson :: ObjectId ( v) => json ! ( { "$oid" : v. to_hex( ) } ) ,
376- Bson :: DateTime ( v) if v. timestamp_millis ( ) >= 0 && v. year ( ) <= 99999 => {
377- let seconds_format = if v. timestamp_subsec_millis ( ) == 0 {
373+ Bson :: DateTime ( v) if v. timestamp_millis ( ) >= 0 && v. 0 . year ( ) <= 99999 => {
374+ let seconds_format = if v. 0 . timestamp_subsec_millis ( ) == 0 {
378375 SecondsFormat :: Secs
379376 } else {
380377 SecondsFormat :: Millis
381378 } ;
382379
383380 json ! ( {
384- "$date" : v. to_rfc3339_opts( seconds_format, true ) ,
381+ "$date" : v. 0 . to_rfc3339_opts( seconds_format, true ) ,
385382 } )
386383 }
387384 Bson :: DateTime ( v) => json ! ( {
@@ -539,15 +536,15 @@ impl Bson {
539536 "$oid" : v. to_string( ) ,
540537 }
541538 }
542- Bson :: DateTime ( v) if v. timestamp_millis ( ) >= 0 && v. year ( ) <= 99999 => {
543- let seconds_format = if v. timestamp_subsec_millis ( ) == 0 {
539+ Bson :: DateTime ( v) if v. timestamp_millis ( ) >= 0 && v. 0 . year ( ) <= 99999 => {
540+ let seconds_format = if v. 0 . timestamp_subsec_millis ( ) == 0 {
544541 SecondsFormat :: Secs
545542 } else {
546543 SecondsFormat :: Millis
547544 } ;
548545
549546 doc ! {
550- "$date" : v. to_rfc3339_opts( seconds_format, true ) ,
547+ "$date" : v. 0 . to_rfc3339_opts( seconds_format, true ) ,
551548 }
552549 }
553550 Bson :: DateTime ( v) => doc ! {
@@ -738,12 +735,12 @@ impl Bson {
738735
739736 [ "$date" ] => {
740737 if let Ok ( date) = doc. get_i64 ( "$date" ) {
741- return Bson :: DateTime ( DateTime :: from_i64 ( date) . into ( ) ) ;
738+ return Bson :: DateTime ( DateTime :: from_millis ( date) ) ;
742739 }
743740
744741 if let Ok ( date) = doc. get_str ( "$date" ) {
745742 if let Ok ( date) = chrono:: DateTime :: parse_from_rfc3339 ( date) {
746- return Bson :: DateTime ( date. into ( ) ) ;
743+ return Bson :: DateTime ( date. with_timezone ( & Utc ) . into ( ) ) ;
747744 }
748745 }
749746 }
@@ -888,7 +885,7 @@ impl Bson {
888885 }
889886
890887 /// If `Bson` is `DateTime`, return its value. Returns `None` otherwise
891- pub fn as_datetime ( & self ) -> Option < & chrono :: DateTime < Utc > > {
888+ pub fn as_datetime ( & self ) -> Option < & crate :: DateTime > {
892889 match * self {
893890 Bson :: DateTime ( ref v) => Some ( v) ,
894891 _ => None ,
@@ -897,7 +894,7 @@ impl Bson {
897894
898895 /// If `Bson` is `DateTime`, return a mutable reference to its value. Returns `None`
899896 /// otherwise
900- pub fn as_datetime_mut ( & mut self ) -> Option < & mut chrono :: DateTime < Utc > > {
897+ pub fn as_datetime_mut ( & mut self ) -> Option < & mut crate :: DateTime > {
901898 match * self {
902899 Bson :: DateTime ( ref mut v) => Some ( v) ,
903900 _ => None ,
@@ -973,76 +970,78 @@ impl Timestamp {
973970 }
974971}
975972
976- /// `DateTime` representation in struct for serde serialization
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+ /// ```
977987///
978- /// Just a helper for convenience
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`].
979993///
980994/// ```rust
981995/// use serde::{Serialize, Deserialize};
982- /// use bson::DateTime;
983996///
984997/// #[derive(Serialize, Deserialize)]
985998/// struct Foo {
986- /// date_time: DateTime,
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>,
9871008/// }
9881009/// ```
9891010#[ derive( Debug , Eq , PartialEq , Ord , PartialOrd , Hash , Copy , Clone ) ]
990- pub struct DateTime ( pub chrono:: DateTime < Utc > ) ;
991-
992- impl DateTime {
993- pub ( crate ) fn from_i64 ( date : i64 ) -> Self {
994- let mut num_secs = date / 1000 ;
995- let mut num_millis = date % 1000 ;
996-
997- // The chrono API only lets us create a DateTime with an i64 number of seconds
998- // and a u32 number of nanoseconds. In the case of a negative timestamp, this
999- // means that we need to turn the negative fractional part into a positive and
1000- // shift the number of seconds down. For example:
1001- //
1002- // date = -4300 ms
1003- // num_secs = date / 1000 = -4300 / 1000 = -4
1004- // num_millis = date % 1000 = -4300 % 1000 = -300
1005- //
1006- // Since num_millis is less than 0:
1007- // num_secs = num_secs -1 = -4 - 1 = -5
1008- // num_millis = num_nanos + 1000 = -300 + 1000 = 700
1009- //
1010- // Instead of -4 seconds and -300 milliseconds, we now have -5 seconds and +700
1011- // milliseconds, which expresses the same timestamp, but in a way we can create
1012- // a DateTime with.
1013- if num_millis < 0 {
1014- num_secs -= 1 ;
1015- num_millis += 1000 ;
1016- } ;
1011+ pub struct DateTime ( chrono:: DateTime < Utc > ) ;
10171012
1018- Utc . timestamp ( num_secs, num_millis as u32 * 1_000_000 )
1019- . into ( )
1013+ impl crate :: DateTime {
1014+ pub ( crate ) fn from_millis ( date : i64 ) -> Self {
1015+ Utc . timestamp_millis ( date) . into ( )
10201016 }
1021- }
10221017
1023- impl Deref for DateTime {
1024- type Target = chrono:: DateTime < Utc > ;
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+ }
10251022
1026- fn deref ( & self ) -> & Self :: Target {
1027- & self . 0
1023+ /// If this DateTime is sub-millisecond precision. BSON only supports millisecond precision, so
1024+ /// this should be checked before serializing to BSON.
1025+ pub ( crate ) fn is_sub_millis_precision ( & self ) -> bool {
1026+ self . 0 . timestamp_subsec_micros ( ) % 1000 != 0
10281027 }
10291028}
10301029
1031- impl DerefMut for DateTime {
1032- fn deref_mut ( & mut self ) -> & mut chrono :: DateTime < Utc > {
1033- & mut self . 0
1030+ impl Display for crate :: DateTime {
1031+ fn fmt ( & self , f : & mut fmt :: Formatter < ' _ > ) -> fmt :: Result {
1032+ Display :: fmt ( & self . 0 , f )
10341033 }
10351034}
10361035
1037- impl From < DateTime > for chrono:: DateTime < Utc > {
1036+ impl From < crate :: DateTime > for chrono:: DateTime < Utc > {
10381037 fn from ( utc : DateTime ) -> Self {
10391038 utc. 0
10401039 }
10411040}
10421041
1043- impl From < chrono:: DateTime < Utc > > for DateTime {
1044- fn from ( x : chrono:: DateTime < Utc > ) -> Self {
1045- DateTime ( x)
1042+ impl < T : chrono :: TimeZone > From < chrono:: DateTime < T > > for crate :: DateTime {
1043+ fn from ( x : chrono:: DateTime < T > ) -> Self {
1044+ DateTime ( x. with_timezone ( & Utc ) )
10461045 }
10471046}
10481047
0 commit comments