chrono
chrono copied to clipboard
Tracking issue: Converting the API to return `Result`s
A list to keep score. Not yet complete, and only lists the public API.
Currently at 61/153.
NaiveDate
- [x]
NaiveDate::from_ymd: #1444 - [x]
NaiveDate::from_yo: #1460 - [x]
NaiveDate::from_isoywd: #1460 - [x]
NaiveDate::from_num_days_from_ce: #1470 - [x]
NaiveDate::from_weekday_of_month: #1512 - [ ]
NaiveDate::parse_from_str - [ ]
NaiveDate::parse_and_remainder - [x]
NaiveDate::and_hms: #1410 - [x]
NaiveDate::and_hms_milli: #1410 - [x]
NaiveDate::and_hms_micro: #1410 - [x]
NaiveDate::and_hms_nano: #1410 - [x]
NaiveDate::succ: #1513 - [x]
NaiveDate::pred: #1513 - [x]
NaiveDate::checked_add_days: #1475 - [x]
NaiveDate::checked_sub_days: #1475 - [x]
NaiveDate::checked_add_months: #1537 - [x]
NaiveDate::checked_sub_months: #1537 - [x]
NaiveDate::checked_add_signed: #1514 - [x]
NaiveDate::checked_sub_signed: #1514 - [x]
NaiveDate::with_year: #1466 - [x]
NaiveDate::with_month: #1509 - [x]
NaiveDate::with_day: #1509 - [x]
NaiveDate::with_ordinal: #1531
NaiveTime
- [x]
NaiveTime::from_hms: #1410 - [x]
NaiveTime::from_hms_micro: #1410 - [x]
NaiveTime::from_hms_milli: #1410 - [x]
NaiveTime::from_hms_nano: #1410 - [x]
NaiveTime::from_num_seconds_from_midnight: #1410 - [ ]
NaiveTime::parse_from_str - [ ]
NaiveTime::parse_and_remainder - [x]
NaiveTime::with_hour: #1498 - [x]
NaiveTime::with_minute: #1498 - [x]
NaiveTime::with_second: #1498 - [x]
NaiveTime::with_nanosecond: #1498
NaiveDateTime
- [ ]
NaiveDateTime::and_local_timezone(toLocalResult) - [ ]
NaiveDateTime::parse_and_remainder - [ ]
NaiveDateTime::parse_from_str - [x]
NaiveDateTime::checked_add_days: #1475 - [x]
NaiveDateTime::checked_sub_days: #1475 - [x]
NaiveDateTime::checked_add_months: #1537 - [x]
NaiveDateTime::checked_sub_months: #1537 - [x]
NaiveDateTime::checked_add_signed: #1514 - [x]
NaiveDateTime::checked_sub_signed: #1514 - [x]
NaiveDateTime::checked_add_offset: #1514 - [x]
NaiveDateTime::checked_sub_offset: #1514 - [x]
NaiveDateTime::with_year: #1466 - [x]
NaiveDateTime::with_month: #1509 - [x]
NaiveDateTime::with_day: #1509 - [x]
NaiveDateTime::with_ordinal: #1531 - [x]
NaiveDateTime::with_hour: #1498 - [x]
NaiveDateTime::with_minute: #1498 - [x]
NaiveDateTime::with_second: #1498 - [x]
NaiveDateTime::with_nanosecond: #1498
NaiveWeek
- [ ]
NaiveWeek::first_day(?) - [ ]
NaiveWeek::last_day(?) - [ ]
NaiveWeek::days(?)
FixedOffset
- [x]
FixedOffset::east: #1468 - [x]
FixedOffset::west: #1468
TimeDelta
- [x]
TimeDelta::new: #1538 - [x]
TimeDelta::milliseconds: #1538 - [x]
TimeDelta::num_microseconds: #1538 - [x]
TimeDelta::num_nanoseconds: #1538 - [ ]
TimeDelta::checked_add: ? - [ ]
TimeDelta::checked_sub: ? - [x]
TimeDelta::from_std: #1538 - [x]
TimeDelta::to_std: #1538
DateTime
- [ ]
DateTime::checked_add_days - [ ]
DateTime::checked_add_months - [ ]
DateTime::checked_add_signed - [ ]
DateTime::checked_sub_days - [ ]
DateTime::checked_sub_months - [ ]
DateTime::checked_sub_signed - [ ]
DateTime::date_naive(?) - [x]
DateTime<Utc>::from_timestamp: #1495 - [x]
DateTime<Utc>::from_timestamp_millis: #1495 - [x]
DateTime<Utc>::from_timestamp_micros: #1495 - [ ]
DateTime::naive_local(?) - [ ]
DateTime<FixedOffset>::parse_from_rfc2822 - [ ]
DateTime<FixedOffset>::parse_from_rfc3339 - [ ]
DateTime<FixedOffset>::parse_from_str - [ ]
DateTime<FixedOffset>::parse_and_remainder - [x]
DateTime::timestamp_nanos: #1495 - [ ]
DateTime::to_rfc2822 - [ ]
DateTime::to_rfc3339 - [ ]
DateTime::with_timezone - [ ]
DateTime::with_year - [ ]
DateTime::with_month - [ ]
DateTime::with_day - [ ]
DateTime::with_ordinal - [ ]
DateTime::with_time - [ ]
DateTime::with_hour - [ ]
DateTime::with_minute - [ ]
DateTime::with_second - [x]
DateTime::with_nanosecond: #1520
TimeZone
- [ ]
TimeZone::offset_from_local_datetime - [ ]
TimeZone::offset_from_utc_datetime - [ ]
TimeZone::from_local_datetime - [ ]
TimeZone::from_utc_datetime - [ ]
TimeZone::timestamp - [ ]
TimeZone::timestamp_micros - [ ]
TimeZone::timestamp_millis - [ ]
TimeZone::timestamp_nanos - [ ]
TimeZone::with_ymd_and_hms
LocalResult
- [ ]
LocalResult::single - [ ]
LocalResult::earliest - [ ]
LocalResult::latest
Parsed
- [ ]
Parsed::set_ampm: #1511 - [ ]
Parsed::set_day: #1511 - [ ]
Parsed::set_hour: #1511 - [ ]
Parsed::set_hour12: #1511 - [ ]
Parsed::set_isoweek: #1511 - [ ]
Parsed::set_isoyear: #1511 - [ ]
Parsed::set_isoyear_div_100: #1511 - [ ]
Parsed::set_isoyear_mod_100: #1511 - [ ]
Parsed::set_minute: #1511 - [ ]
Parsed::set_month: #1511 - [ ]
Parsed::set_nanosecond: #1511 - [ ]
Parsed::set_offset: #1511 - [ ]
Parsed::set_ordinal: #1511 - [ ]
Parsed::set_second: #1511 - [ ]
Parsed::set_timestamp: #1511 - [ ]
Parsed::set_week_from_mon: #1511 - [ ]
Parsed::set_week_from_sun: #1511 - [ ]
Parsed::set_weekday: #1511 - [ ]
Parsed::set_year: #1511 - [ ]
Parsed::set_year_div_100: #1511 - [ ]
Parsed::set_year_mod_100: #1511 - [ ]
Parsed::to_datetime - [ ]
Parsed::to_datetime_with_timezone - [ ]
Parsed::to_fixed_offset - [ ]
Parsed::to_naive_date - [ ]
Parsed::to_naive_datetime_with_offset - [ ]
Parsed::to_naive_time
StrftimeItems
- [ ]
StrftimeItems::parse - [ ]
StrftimeItems::parse_to_owned
Other
- [ ]
format::parse - [ ]
format::parse_and_remainder
FromStr implementations
- [ ]
NaiveDate - [ ]
NaiveTime - [ ]
NaiveDateTime - [ ]
DateTime<FixedOffset> - [ ]
DateTime<Utc> - [ ]
DateTime<Local> - [ ]
FixedOffset - [ ]
Weekday - [ ]
Month
TryFrom implementations
- [ ]
TryFrom<u8> for Weekday: :sun_with_face: - [ ]
TryFrom<u8> for Month: :sun_with_face: - [x]
TryFrom<SystemTime> for DateTime<Utc>: #1524 - [ ]
TryFrom<SystemTime> for DateTime<Local> - [x]
TryFrom<DateTime<Tz>> for SystemTime: #1524 - [ ]
From<DateTime<Utc>> for DateTime<Local> - [ ]
From<DateTime<FixedOffset>> for DateTime<Local>
For bonus points, make this more like a dependency tree?
That would be cool to have, but it is more a dependency graph than a tree.
Those are kind of the same thing IMO -- unless you expect there are a bunch of cycles in there?
I'll add a :sun_with_face: after items when I think they are ready to convert without deep dependencies.
@Zomtir What would you like to work on next, if any? Then I'll stay clear.
Unfortunately I am occupied for the next three weeks. I will rebase the checked_(add/sub)_days once I am home and have to take a break then.
Thank you for everything until now :+1:.
Well... I lied. The succ/pred caught my eye and I could not resist. Uno mas: #1513
Please also all the try_... APIs. Returning Option makes it impossible to use the ? operator properly, as the returned None is not connected to the chrono crate at all.
Also, please have the Err value include the erroneous input value for the try_... functions. Otherwise, functional code style becomes annoying.
Example
Currently, the try_... functions can only be used as follows:
let duration_seconds = input_function();
let duration = Duration::try_seconds(duration_seconds).ok_or(Error::TimeRangeError(duration_seconds))?;
Ideally however, it would work as follows:
impl From<ChronoTimeRangeError> for Error {
fn from(ChronoTimeRangeError {value}: ChronoTimeRangeError) {
Error::TimeRangeError(value)
}
}
fn foo() -> Result<(), Error> {
let duration = Duration::try_seconds(input_function())?;
}
This issue is for the next major version of chrono, 0.5. All deprecated methods are removed, and the _opt and try_ methods are renamed. @ISibboI In this case you may be interested in #1515 which was just merged.
Sorry, I was on mobile and just saw this part of your comment:
Also, please have the
Errvalue include the erroneous input value for thetry_...functions. Otherwise, functional code style becomes annoying.
Interesting example! I'm afraid that is going to be very difficult. We are currently converting ca. 150 methods. To make them all return the erroneous input asks for multiple error types or an error type that is generic. And we can no longer simply bubble up errors within chrono but have to map them to include the input at the outermost method. It is too big a change for me on what is already a bit complex and interwoven work to consider.
I will attempt TimeDelta::checked_add and TimeDelta::checked_sub now.
Great!
Honestly we are currently out of methods that are ready to convert. Converting the parsing methods depends on #1511, and the first preparations towards converting the methods that depend on the TimeZone trait depend on #1529. As soon as those are in we can pick up work here.
I'm not sure if we want to convert TimeDelta::checked_add and TimeDelta::checked_sub. The same methods on integers return an Option. We may want to follow that for this type too. What do you think?
It does seem very weird to hide different errors behind None. If TimeDelta::new or to a greater extent all functions of TimeDelta returned the same error, the mapping to None would be bijective.
For integers (unit-less scalar) the overall concept might be simpler than TimeDelta, which can be converted to different units of time.
Appending .ok() also isn't too much to ask for the user in checked_add().ok().
So most methods on TimeDelta are converted for that reason.
checked_add and checked_sub only fail on overflow. I have no strong opinion, but keeping a similar signature to the corresponding methods from the standard library is something to consider.
Partly related, but I noticed quite a few unchecked operations in TimeDelta:
impl Mul<i32> for TimeDelta {
type Output = TimeDelta;
fn mul(self, rhs: i32) -> TimeDelta {
// Multiply nanoseconds as i64, because it cannot overflow that way.
let total_nanos = self.nanos as i64 * rhs as i64;
let (extra_secs, nanos) = div_mod_floor_64(total_nanos, NANOS_PER_SEC as i64);
let secs = self.secs * rhs as i64 + extra_secs;
TimeDelta { secs, nanos: nanos as i32 }
}
}
The downcasting from i64 to i32 will wrap on overflow, which should be the same result as directly multiplying two i32. Both are standard behaviour of integers, but I wonder if this is acceptable for TimeDelta.
Do you mean nanos as i32? The result of value % NANOS_PER_SEC should always be less than NANOS_PER_SEC.
Do you mean
nanos as i32? The result ofvalue % NANOS_PER_SECshould always be less thanNANOS_PER_SEC.
My bad, nanos are covered. let secs = self.secs * rhs could be (2^63)*(2^31) potentially? Not that it will remotely matter, just asking if this intended.
The point I'm trying to make is that integer behaviour is not always applicable, so I don't know if checked_add should be the held to that restriction. If there was a common trait that we could implement that would make more sense.
Personally I'd find internal consistency preferable, e.g having
addandmulreturnTimeDeltachecked_addandchecked_mulreturnResult<TimeDelta>
But in the greater context this is splitting hairs and we should focus on the bigger targets atm. Let me know if there is something do.
My bad,
nanosare covered.let secs = self.secs * rhscould be(2^63)*(2^31)potentially? Not that it will remotely matter, just asking if this intended.
Good point! self.secs is at most something like 2^44, but that still remains an easy way to create invalid TimeDeltas and is definitely something to fix. Want to make a PR for mul? And potentially add checked_mul (against the main branch)?