-
Notifications
You must be signed in to change notification settings - Fork 144
RUST-1129 Make the dependency on chrono
optional and provide equivalent time
interop
#352
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RUST-1129 Make the dependency on chrono
optional and provide equivalent time
interop
#352
Conversation
src/datetime.rs
Outdated
use std::result::Result; | ||
match self.to_time().format(&Rfc3339) { | ||
Result::Ok(s) => s, | ||
Result::Err(e) => e.to_string(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not thrilled about handling the error this way but I couldn't think of a better option that wouldn't be a breaking change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
given that the chrono equivalent never errored, any idea what can lead this method to fail / how likely we are to encounter this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From the source, the time
method fails if the year is outside [0,9999]; the chrono equivalent doesn't have that check.
The time
method has some other potential failure cases as well since it's a more general method, but for the specific purpose of formatting an OffsetDateTime
I don't think they can happen.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmmm, should we consider deprecating this method in favor of a new version that propagates the error correctly? seems like it might help cut down on the chances anyone hits this weirdness
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The time
crate actually has a large-dates
flag which expands this to +-99,999, which we may want to consider enabling here, as MongoDB technically supports any date that can be represented as an i64
from the Unix epoch. Should we enable that flag, we'll want to let the maintainer know of our use case here so that the feature flag stays around in the future.
Also, rather than erroring, it may be more appropriate to panic here. Could we test some inputs that error in time
and see if they panic in chrono
? If they do it might be okay for us to panic here as well. Another option would be to cap the date to time
's maximum value and use that for the date here. I think we do that in a few places already with chrono
's maximum date. If none of those work, then I agree we probably should deprecate this method and introduce a new one, since I think including error information as a String could be pretty cumbersome or dangerous.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that solution SGTM. since we use the flag already it probably seems worth chiming in on that discussion linked above to let them know why
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And as a last check, are we okay with the risk of breaking user code with this? It's technically possible that a user has a super large date in their DB somewhere that used to format okay but will panic now via this method or fail to serialize via the serde helper.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the risk is okay here - we're being loud about this change with the deprecation warning, and I think we should also call it out in the patch notes. It's also worth considering that the RFC itself is explicit about only applying to years in the 0000-9999 range and that the year field is fixed at four digits, so the chrono implementation is producing output that's probably not going to be accepted elsewhere.
That said, I'd be interested to hear if @kmahar or @isabelatkinson have other opinions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh nice, I didn't know that about the RFC, that definitely makes this change seem fine to me then.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
agree it seems fine 👍
})? | ||
.into(); | ||
Ok(crate::DateTime::from_chrono(datetime)) | ||
let datetime = crate::DateTime::parse_rfc3339_str(date.as_str()).map_err(|_| { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here and elsewhere I changed it from the "parse into external datetime, convert to bson datetime" pattern to just directly using the methods bson::DateTime
provides.
src/bson.rs
Outdated
@@ -430,7 +437,7 @@ impl Bson { | |||
}) | |||
} | |||
Bson::ObjectId(v) => json!({"$oid": v.to_hex()}), | |||
Bson::DateTime(v) if v.timestamp_millis() >= 0 && v.to_chrono().year() <= 99999 => { | |||
Bson::DateTime(v) if v.timestamp_millis() >= 0 && v.to_time().year() <= 99999 => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if the year constraint here is correct - it's different than the one below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
from my reading of the extJSON spec we should drop a 9 here to match below... see datetime entries in this table.
I was wondering how we would pass the corresponding corpus test, but it looks like that test case does not have a relaxed extJSON version specified so we likely make no assertions on it -- maybe it's omitted because it's the same as the canonical, but IMO it seems like test runners should probably confirm their relaxed output in that case matches canonical. perhaps we should add an assertion to our corpus runner so that for a test case with no expected relaxed output, we check that the relaxed output is equal to the expected canonical output?
if that just works, I'd propose we file a DRIVERS ticket that suggests amending the corpus spec to require this assertion.
thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like that doesn't just work, unfortunately. I filed RUST-1261 to follow up on that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looking good! just a few questions/thoughts
src/bson.rs
Outdated
@@ -430,7 +437,7 @@ impl Bson { | |||
}) | |||
} | |||
Bson::ObjectId(v) => json!({"$oid": v.to_hex()}), | |||
Bson::DateTime(v) if v.timestamp_millis() >= 0 && v.to_chrono().year() <= 99999 => { | |||
Bson::DateTime(v) if v.timestamp_millis() >= 0 && v.to_time().year() <= 99999 => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
from my reading of the extJSON spec we should drop a 9 here to match below... see datetime entries in this table.
I was wondering how we would pass the corresponding corpus test, but it looks like that test case does not have a relaxed extJSON version specified so we likely make no assertions on it -- maybe it's omitted because it's the same as the canonical, but IMO it seems like test runners should probably confirm their relaxed output in that case matches canonical. perhaps we should add an assertion to our corpus runner so that for a test case with no expected relaxed output, we check that the relaxed output is equal to the expected canonical output?
if that just works, I'd propose we file a DRIVERS ticket that suggests amending the corpus spec to require this assertion.
thoughts?
src/datetime.rs
Outdated
use std::result::Result; | ||
match self.to_time().format(&Rfc3339) { | ||
Result::Ok(s) => s, | ||
Result::Err(e) => e.to_string(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
given that the chrono equivalent never errored, any idea what can lead this method to fail / how likely we are to encounter this?
src/datetime.rs
Outdated
use std::result::Result; | ||
match self.to_time().format(&Rfc3339) { | ||
Result::Ok(s) => s, | ||
Result::Err(e) => e.to_string(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The time
crate actually has a large-dates
flag which expands this to +-99,999, which we may want to consider enabling here, as MongoDB technically supports any date that can be represented as an i64
from the Unix epoch. Should we enable that flag, we'll want to let the maintainer know of our use case here so that the feature flag stays around in the future.
Also, rather than erroring, it may be more appropriate to panic here. Could we test some inputs that error in time
and see if they panic in chrono
? If they do it might be okay for us to panic here as well. Another option would be to cap the date to time
's maximum value and use that for the date here. I think we do that in a few places already with chrono
's maximum date. If none of those work, then I agree we probably should deprecate this method and introduce a new one, since I think including error information as a String could be pretty cumbersome or dangerous.
src/datetime.rs
Outdated
use std::result::Result; | ||
match self.to_time().format(&Rfc3339) { | ||
Result::Ok(s) => s, | ||
Result::Err(e) => e.to_string(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And as a last check, are we okay with the risk of breaking user code with this? It's technically possible that a user has a super large date in their DB somewhere that used to format okay but will panic now via this method or fail to serialize via the serde helper.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm mod patrick's renaming comment!
RUST-1129
This PR swaps out the internal operations that used
chrono
for equivalent ones usingtime
, makes thechrono
dependency optional, and adds optional interop methods fortime
structs.