-
Notifications
You must be signed in to change notification settings - Fork 790
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
Add jiff into/from python convertions #4823
Conversation
fbaa090
to
1d2bc30
Compare
Jiff requires rust 1.70 or newer, but pyo3's minimum version is 1.63.0. Is it acceptable to increase our msrv or can we make this conditional somehow? |
5b523f0
to
c82a970
Compare
I don't think we can bump MSRV, but having an off-by-default feature, which requires a newer version is probably ok (if we document that). I think this therefore requires changes in the testing workflows, because it can't be part of |
Fixed the CI and all other TODO's so it is ready for review |
c0e5ddb
to
d2e6ac6
Compare
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.
Thank you! This looks good to me, just some minor comments.
src/conversions/jiff.rs
Outdated
let fold = match ambiguous_offset { | ||
AmbiguousOffset::Unambiguous { .. } => false, | ||
AmbiguousOffset::Fold { after, .. } => after == self.offset(), | ||
AmbiguousOffset::Gap { .. } => unreachable!(), |
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.
Could you add a comment here on why this is unreachable.
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's my attempt:
// This case isn't reachable because if it were, it
// would imply that the `Zoned` value has a civil
// time that never appears on a clock in this time
// zone. Jiff's API prevents this from happening,
// so this case is unreachable.
An alternative for discovering whether a datetime is in a fold or not might be to use the new TimeZone::preceding
and TimeZone::following
APIs. It's likely faster but more difficult to get right. The way it's done here is probably the clearest way to do it given Jiff's current API.
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.
Sounds good to me 👍, thank you for the suggestion!
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.
An alternative for discovering whether a datetime is in a fold or not might be to use the new TimeZone::preceding and TimeZone::following APIs.
Switched to the TimeZone iter API & added a proptest to verify. 👍
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 might be a nice api addition to jiff if one could get the start timestamp of the current offset transition.
I currently do it using the following snippet but it could probably be done cleaner with some internal api?
let prev = zoned.time_zone().preceding(zoned.timestamp()).next()?;
let start_of_current_offset = zoned
.time_zone()
.following(prev.timestamp())
.next()?
.timestamp();
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 that's actually not quite right. Try this:
use jiff::tz::{TimeZone, TimeZoneTransition};
fn main() -> anyhow::Result<()> {
let tz = TimeZone::system();
let zdt = jiff::Zoned::now();
let cur = current_transition(&tz, zdt.timestamp()).unwrap();
dbg!(cur.timestamp().to_zoned(tz));
Ok(())
}
fn current_transition(
tz: &TimeZone,
ts: jiff::Timestamp,
) -> Option<TimeZoneTransition> {
let prev = tz.preceding(ts).next()?;
let next = tz.following(ts).next()?;
if next.timestamp() == ts {
Some(next)
} else {
Some(prev)
}
}
Jiff actually doesn't have any internal APIs that would make this easier. It might be worth adding a new routine for this, but I'd like to see how common the need is for it first.
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.
When ts is exactly on a timezone transition both preceding
and following
will not contain the current transition. preceding
will contain all transitions strictly earlier and following
will contain all transitions strictly after the current one. So it is impossible for the case 2020-10-25T01:00:00+00:00[Europe/London]
to get the current transition without going back one transition and going forward again.
zoned: 2020-10-25T01:00:00+00:00[Europe/London]
zoned.timestamp(): 2020-10-25T01:00:00Z
next.timestamp(): 2021-03-28T01:00:00Z
prev.timestamp(): 2020-03-29T01:00:00Z
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.
Yeah my code does do that! But I did indeed have a bug in it. Try this instead:
fn current_transition(
tz: &TimeZone,
ts: Timestamp,
) -> Option<TimeZoneTransition> {
let prev = tz.preceding(ts).next()?;
let next = tz.following(prev.timestamp()).next()?;
if next.timestamp() == ts {
Some(next)
} else {
Some(prev)
}
}
That should work. In your original code, you go back and forward unconditionally, which only works in the case where the original timestamp is precisely at the boundary. But the above snippet only uses next
(after going back) if the given timestamp is at the boundary, otherwise, the immediately previous transition is the correct one.
Your code is correct if you know the timestamp given is always at a boundary.
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.
Thanks you are right and thanks for pointing this out. Code looks way cleaner this way.
Cargo.toml
Outdated
@@ -39,6 +39,7 @@ either = { version = "1.9", optional = true } | |||
eyre = { version = ">= 0.6.8, < 0.7", optional = true } | |||
hashbrown = { version = ">= 0.14.5, < 0.16", optional = true } | |||
indexmap = { version = ">= 2.5.0, < 3", optional = true } | |||
jiff = { version = "0.1.17", optional = true } |
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 would suggest ensuring that the feature is named jiff-01
, either by introducing a new feature or renaming the package. For example, this is what rust-postgres
does.
This ensures there is a paved path to supporting multiple versions of Jiff when a semver incompatible release comes out without making a semver incompatible release of pyo3
.
Arguably, this ought to be done for other dependencies, but maybe they don't do incompatible releases often. For Jiff, I'd like get 1.0 out this summer, and then it should sit there for a long while.
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's a good idea (especially if we know there will be a major version bump soon-ish), thanks for bringing that up. Renaming the package looks like a good option to me.
We should also add this to the feature docs in the guide, and mention the different MSRV for this feature there. |
It might be worth waiting on this a little bit. I'm planning to get a My plan is to get |
0883ab8
to
aa2a4ba
Compare
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 might be worth waiting on this a little bit. I'm planning to get a
jiff 0.2
release out in the next month or so.
I'd be fine with that. (Something like ">= 0.1, < 0.3" could also be an option, but that depends on the changes)
4f71daa
to
0dba0f5
Compare
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.
Thanks, this is looking good to me (I didn't manage to read the meat of the conversions in much depth, it looks like they have already been reviewed, thanks @Icxolu).
I'm ok with either merging this for jiff 0.1 or waiting until jiff 0.2 as you prefer @bschoenmaeckers.
Just a few small thoughts.
src/types/datetime_abi.rs
Outdated
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.
Maybe this is better named as datetime_abi3
? It's not really an ABI here but it is code specific to how we deal with abi3
.
noxfile.py
Outdated
jiff_features_set = (("--features=jiff-01",), ("--features=jiff-01 abi3",)) | ||
for feature_set in _get_feature_sets() + jiff_features_set: |
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 clippy jobs are already quite slow. Rather than adding additional jobs here, please can you modify _get_feature_sets()
to be rust version aware and only set the jiff feature if the compiler is new enough?
//! # Example: Convert a `datetime.datetime` to jiff `Zoned` | ||
//! | ||
//! ```rust | ||
//! # use jiff_01 as jiff; |
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.
You might need to cfg this doctest as not windows, IIRC windows needs a tzdata
package but it's quite a faff to bother requiring it.
2d1427d
to
d3e4fb4
Compare
I'm fine by merging it for 0.1, adding support for 0.2 should be very easy when the time comes. |
6ac96ca
to
a7b26a3
Compare
a53a115
to
c2dcb3a
Compare
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.
Thanks again for implementing! Let's get this merged now 🚀
Looks like the feature combinations for CI are not quite right yet. |
Please try again |
closes #4510