21
21
22
22
//! BSON definition
23
23
24
- use std:: {
25
- fmt:: { self , Debug , Display } ,
26
- ops:: { Deref , DerefMut } ,
27
- } ;
24
+ use std:: fmt:: { self , Debug , Display } ;
28
25
29
26
use chrono:: { Datelike , SecondsFormat , TimeZone , Utc } ;
30
27
use serde_json:: { json, Value } ;
@@ -68,7 +65,7 @@ pub enum Bson {
68
65
/// [ObjectId](http://dochub.mongodb.org/core/objectids)
69
66
ObjectId ( oid:: ObjectId ) ,
70
67
/// UTC datetime
71
- DateTime ( chrono :: DateTime < Utc > ) ,
68
+ DateTime ( crate :: DateTime ) ,
72
69
/// Symbol (Deprecated)
73
70
Symbol ( String ) ,
74
71
/// [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 {
290
287
291
288
impl From < chrono:: DateTime < Utc > > for Bson {
292
289
fn from ( a : chrono:: DateTime < Utc > ) -> Bson {
293
- Bson :: DateTime ( a )
290
+ Bson :: DateTime ( DateTime ( a ) )
294
291
}
295
292
}
296
293
@@ -373,15 +370,15 @@ impl Bson {
373
370
} )
374
371
}
375
372
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 {
378
375
SecondsFormat :: Secs
379
376
} else {
380
377
SecondsFormat :: Millis
381
378
} ;
382
379
383
380
json ! ( {
384
- "$date" : v. to_rfc3339_opts( seconds_format, true ) ,
381
+ "$date" : v. 0 . to_rfc3339_opts( seconds_format, true ) ,
385
382
} )
386
383
}
387
384
Bson :: DateTime ( v) => json ! ( {
@@ -539,15 +536,15 @@ impl Bson {
539
536
"$oid" : v. to_string( ) ,
540
537
}
541
538
}
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 {
544
541
SecondsFormat :: Secs
545
542
} else {
546
543
SecondsFormat :: Millis
547
544
} ;
548
545
549
546
doc ! {
550
- "$date" : v. to_rfc3339_opts( seconds_format, true ) ,
547
+ "$date" : v. 0 . to_rfc3339_opts( seconds_format, true ) ,
551
548
}
552
549
}
553
550
Bson :: DateTime ( v) => doc ! {
@@ -738,12 +735,12 @@ impl Bson {
738
735
739
736
[ "$date" ] => {
740
737
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) ) ;
742
739
}
743
740
744
741
if let Ok ( date) = doc. get_str ( "$date" ) {
745
742
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 ( ) ) ;
747
744
}
748
745
}
749
746
}
@@ -888,7 +885,7 @@ impl Bson {
888
885
}
889
886
890
887
/// 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 > {
892
889
match * self {
893
890
Bson :: DateTime ( ref v) => Some ( v) ,
894
891
_ => None ,
@@ -897,7 +894,7 @@ impl Bson {
897
894
898
895
/// If `Bson` is `DateTime`, return a mutable reference to its value. Returns `None`
899
896
/// 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 > {
901
898
match * self {
902
899
Bson :: DateTime ( ref mut v) => Some ( v) ,
903
900
_ => None ,
@@ -973,76 +970,78 @@ impl Timestamp {
973
970
}
974
971
}
975
972
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
+ /// ```
977
987
///
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`].
979
993
///
980
994
/// ```rust
981
995
/// use serde::{Serialize, Deserialize};
982
- /// use bson::DateTime;
983
996
///
984
997
/// #[derive(Serialize, Deserialize)]
985
998
/// 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>,
987
1008
/// }
988
1009
/// ```
989
1010
#[ 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 > ) ;
1017
1012
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 ( )
1020
1016
}
1021
- }
1022
1017
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
+ }
1025
1022
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
1028
1027
}
1029
1028
}
1030
1029
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 )
1034
1033
}
1035
1034
}
1036
1035
1037
- impl From < DateTime > for chrono:: DateTime < Utc > {
1036
+ impl From < crate :: DateTime > for chrono:: DateTime < Utc > {
1038
1037
fn from ( utc : DateTime ) -> Self {
1039
1038
utc. 0
1040
1039
}
1041
1040
}
1042
1041
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 ) )
1046
1045
}
1047
1046
}
1048
1047
0 commit comments