Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/datetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,16 @@ impl crate::DateTime {
self.to_chrono()
.to_rfc3339_opts(chrono::SecondsFormat::AutoSi, true)
}

/// Convert the given RFC 3339 format string to a [`DateTime`].
pub fn from_rfc3339(s: impl AsRef<str>) -> Result<Self, crate::de::Error> {
match chrono::DateTime::<chrono::FixedOffset>::parse_from_rfc3339(s.as_ref()) {
Ok(d) => Ok(Self::from_chrono(d)),
Err(e) => Err(crate::de::Error::InvalidTimestamp {
message: e.to_string(),
}),
}
}
}

impl fmt::Debug for crate::DateTime {
Expand Down
7 changes: 7 additions & 0 deletions src/de/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ pub enum Error {
/// while decoding a UTF-8 String from the input data.
InvalidUtf8String(string::FromUtf8Error),

/// An error encountered during the conversion of one datetime format to another.
InvalidTimestamp {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rather than reusing the deserialization error here, I wonder if it would be better to introduce another error type for datetimes like we have for ObjectIds (oid::Error, returned from ObjectId::parse_str) and UUIDs (uuid::Error, returned from Uuid::parse_str). It's unfortunate that this crate has so many error types, but I think it's something we probably have to commit to at this point.

cc @abr-egn @isabelatkinson

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that seems fine to me for the sake of consistency

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added an error enum and switched over to using that instead in 0bd1b00.

/// A message describing the error.
message: String,
},

/// While decoding a `Document` from bytes, an unexpected or unsupported element type was
/// encountered.
#[non_exhaustive]
Expand Down Expand Up @@ -55,6 +61,7 @@ impl fmt::Display for Error {
match *self {
Error::Io(ref inner) => inner.fmt(fmt),
Error::InvalidUtf8String(ref inner) => inner.fmt(fmt),
Error::InvalidTimestamp { ref message } => message.fmt(fmt),
Error::UnrecognizedDocumentElementType {
ref key,
element_type,
Expand Down
21 changes: 21 additions & 0 deletions src/tests/datetime.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use std::str::FromStr;

#[test]
fn rfc3339_to_datetime() {
let rfc = "2020-06-09T10:58:07.095Z";
let date = chrono::DateTime::<chrono::Utc>::from_str(rfc).unwrap();
assert_eq!(
crate::DateTime::from_rfc3339(rfc).unwrap(),
crate::DateTime::from_chrono(date)
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we add an assertion that converting the datetime back to a string matches the input?

}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it'd be good to also have a test to validate failure behavior - doesn't need to assert on the exact error message, just that one is returned for invalid input.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added invalid test cases in 7bcb901.


#[test]
fn invalid_rfc3339_to_datetime() {
let a = "2020-06-09T10:58:07-095Z";
let b = "2020-06-09T10:58:07.095";
let c = "2020-06-09T10:62:07.095Z";
assert!(crate::DateTime::from_rfc3339(a).is_err());
assert!(crate::DateTime::from_rfc3339(b).is_err());
assert!(crate::DateTime::from_rfc3339(c).is_err());
}
1 change: 1 addition & 0 deletions src/tests/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
mod binary_subtype;
mod datetime;
mod modules;
mod serde;
mod spec;
Expand Down