-
Notifications
You must be signed in to change notification settings - Fork 111
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
Adding Result/Error constructs to tzrs
feature in spinoso-time
#1927
Conversation
@lopopolo I've done some digging, and it doesn't look like there are any "good" options for doing checked add on the datetimes. I was somewhat surprise there wasn't something like
This would end us in situations of
And I didn't try it until just now, but I see rust doesn't like function overloading (thank goodness), so this means just impl functions won't cut it. My thoughts is implementing a trait:
Chrono currently uses Do you have any other bright[er] ideas than implementing this trait? |
For these cases, I think we can just implement I don't think the complexity of a trait is worth it here, especially because in the trampolines for Then if we still want to implement |
Funnily enough, it's not supported (in ruby 2.6.3, and also in 3.1.2):
A couple of options:
I'm in favour of Either way, documenting here for posterity, but i'll add |
let invalid_fixed_strings = [ | ||
"+01:010", "+010:10", "+010:010", "0110", "01:10", "01-10", "+01-10", "+01::10", | ||
]; | ||
|
||
for invalid_string in invalid_fixed_strings { |
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.
yay table-driven tests.
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.
hah yes! I was going to ask whether there is a style preference here. The same thing could be done with other tests and cheap hashmap tables (or a tuple lists i guess).
Add but Time subtraction is supported!
I'm in favor of this, but with the caveat that |
Let's impl these APIs in terms of So something like: let float = ...;
let duration = spinoso_time::duration_from_f64(float)
.or_else(|| {
float.checked_neg().and_then(spinoso_time::duration_from_f64)
})
.ok_or_else(|| FloatDomainError::with_message("out of range")?; Or maybe |
I've got one better I think (psuedo codeish): fn checked_add(&self, value: Duration) -> Self {
//magic
}
fn checked_add_f64(&self, value: f64) -> Self {
let nanos = nanos_from_float(value);
let duration = Duration::new(value.abs().floor(), nanos);
if value > 0 {
self.checked_add(duration)
} else {
self.checked_sub(duration)
}
} |
ef35066
to
bc0b159
Compare
this looks mostly good so far and I think you've got a solution to the |
Co-authored-by: Ryan Lopopolo <rjl@hyperbo.la>
These functions all could overflow the number of seconds and/or could cause issues when genreating new Time's. All functions return TimeError since these are functions returning new Time instances, not Math instances (which don't exist)
tzrs
feature in spinoso-timetzrs
feature in spinoso-time
The previous changes I had were getting very specific and causing addition unneeded complexity. Instead of abstracting across many classes, pulling it all together into one place
|
||
/// A wrapper around some of the errors provided by `tz-rs`. | ||
#[allow(clippy::module_name_repetitions)] | ||
#[derive(Debug)] |
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.
can this enum derive Clone
?
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.
Not unless we make some PRs into tz-rs. the wrapped tz-rs errors don't implement it at present unfortunately.
let found_date_times = DateTime::find(year, month, day, hour, minute, second, nanoseconds, tz)?; | ||
|
||
// .latest() will always return Some(DateTime) | ||
let dt = found_date_times.latest().expect("No datetime found with this offset"); |
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.
is this expect guaranteed to not panic?
The docs for DateTime::find
and its return type FoundDateTimeList
indicate that the returned result may be empty:
https://docs.rs/tz-rs/latest/tz/datetime/struct.FoundDateTimeList.html
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.
Yes, I think that's true only when using .unique
after having a look at the underlying implementation. .latest
will always return a result that we're able to work with luckily enough!
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.
/// Returns the latest found date time if existing
pub fn latest(&self) -> Option<DateTime> {
// Found date times are computed in ascending order of Unix times
match *self.0.last()? {
FoundDateTimeKind::Normal(date_time) => Some(date_time),
FoundDateTimeKind::Skipped { after_transition, .. } => Some(after_transition),
}
}
that self.0.last()?
means that if the vec in self.0
is empty, None
is returned. We can leave this for now, but I'd love to maybe find a test case for this empty vec scenario.
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.
Hah, yes, good point!
I'll do some more digging through the generation and the tests there, there must be a use case where it does indeed fail. If it exists, I will find it 😄
Co-authored-by: Ryan Lopopolo <rjl@hyperbo.la> The removal of the checked_add_[i|u][8|16|32] is there since we can leave this easily up to the caller.
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.
Two missing .
in some doc comments but this is good to go! Thanks for pushing this through. This is a final approval, merge whenever you feel comfortable (you don't need to kick it back to me if you fix the typos).
🎉
Co-authored-by: Ryan Lopopolo <rjl@hyperbo.la>
#1902 Added a new backend - however some of the idiomatic principles weren't followed. Specifically there are some
From
impls which can panic - These sorts of things should beTryFrom
as an example.This PR fixes a number of these issues. Specifically it aims to achieve these:
ops
would ideally bechecked_add
andchecked_sub
due to overflowsOffset::fixed()
should be fallible (range +/- 246060)Offset::from(&str)
should be fallibleOffset::from(&str)
tests should also test out of bound Regexs (e.g.+HH:MMM
,HHMM
,/HH-MM
,+HHH:MM
,+HH::MM
)Offset::from(&str)
should not accept+0060
,+2400
timezones. (they are out of range).- [ ] Attempt to unify the errors across chrono and tz-rs since things like(This makes more sense to try after we align some errors)ComponentOutOfRangeError
might be sharable nowTimeError
instead ofTimeErr