time-rs / time

The most used Rust library for date and time handling.
https://time-rs.github.io
Apache License 2.0
1.06k stars 261 forks source link

Advanced date arithmetic functionality #593

Closed HubertK05 closed 1 year ago

HubertK05 commented 1 year ago

First of all, thank you for maintaining a crate that has proven very useful many times in my projects.

However, I think what this crate lacks is more advanced and high-level date arithmetic that can make writing code related to time calculations easier.

Examples

I believe this would be a great addition for this crate because operations on dates can be quite daunting because of all the inconsistencies in time units, like month lengths and leap years.

Also, this idea is quite general and would make for a very large contribution, so if you are interested, I could elaborate on some arithmetic features more specifically.

If this sounds like a good idea, I could try to contribute to it.

jhpratt commented 1 year ago

Overall, this is something I absolutely want to support.

advance several months using one method or something simpler in general instead of having to manually calculate the target month and year

Unquestionably useful. The current problem is that Duration is represented as seconds and nanosecond and months vary in length, preventing their representation. My intent is to introduce another type that is more general, though I'm not yet set on the name.

calculate the first/nth occurence of weekday for a given month

Interestingly, this is something I have ported from C not too long ago. I haven't pushed it to any repository, but the code already exists!

get the next/previous/nth weekday relative to a given point in time

Definitely doable, and shouldn't involve a ton of effort, relatively speaking.

being able to get the time when a day/month/year starts (so basically rounding to given time units

This can be done now using the various replace_X methods. The linked PR is quite a bit different than what you're saying.


If you are interested in working on this, I'd start with the next/previous/nth weekday. That should serve as a decent introduction to the repository and would be uncontroversial. The API would be something like

impl Date {
    fn next_occurrence(self, weekday: Weekday) -> Self;
    fn prev_occurrence(self, weekday: Weekday) -> Self;
    fn nth_next_occurrence(self, weekday: Weekday, n: u8) -> Self;
    fn nth_prev_occurrence(self, weekday: Weekday, n: u8) -> Self;
}

Not sure on the order of weekday and n for the last two.

Let me know if you'd like any assistance with this!

HubertK05 commented 1 year ago

That's awesome! I'm going to work on my pr, and also inttroduce several other ideas:

I think that the order of parameters in the nth_next_occurence/nth_prev_occurence is subjective. Both seem natural to me, and I'll go with the suggested order.

I also have several questions. Could nth_next occurence and similar methods be implemented in PrimitiveDateTime and OffsetDateTime, with their implementation preserving their time and offset, or should I stick to Date only? And will these methods have their checked counterparts? Because adding or subtracting something from a Date can result in an overflow. Finally, which region these methods belong to? I haven't found any region that would fully suit these methods.

jhpratt commented 1 year ago

Weekday has a nth_next method. Why not introduce it to Month, too?

Go for it. It's probably best for organization if introducing nth_next and nth_prev on Month are in a separate PR. Although now I see that there is no nth_prev on Weekday, which is definitely an omission.

  • Get a number of occurences of a given weekday in a given year (and/or year + month)

Let's hold off on this. While it may be good information to have in certain circumstances, it seems like it could be a bit niche. I also don't immediately think of (or know of) a way to calculate this directly.

  • Get the weekday of the first day in a year (and/or month)

This can be done today with Date::weekday, no?

Could nth_next occurence and similar methods be implemented in PrimitiveDateTime and OffsetDateTime, with their implementation preserving their time and offset, or should I stick to Date only?

I would stick with Date only, as the behavior on other types could be somewhat confusing.

And will these methods have their checked counterparts? Because adding or subtracting something from a Date can result in an overflow.

I'm torn on this. Perhaps introduce a checked method, just using .expect() (or realistically the macro to do the same thing in const context). This would make it trivial to export if it is ultimately desired.

Finally, which region these methods belong to?

For the methods on Month, I'd place them immediately after the existing next and prev methods, just as they are with Weekday. For Date, I think the best place would be immediately after next_day and previous_day, as those are the closest equivalents that exist today.