rust-rrule icon indicating copy to clipboard operation
rust-rrule copied to clipboard

Allow `RRuleIter` state to be saved

Open ralpha opened this issue 4 years ago • 2 comments

I was thinking about a way to we can have a RRuleIter and make it iterate over the different dates, but at some point save it so we can later resume iterations where we left of.

This is a tricky problem as just changing the start date (DTSTART) does not work. Because it might result in different result dates. But this can however be done if the start date is equal to a date in the generated dates.

Lets say you have: DTSTART:20210101T090000\nRRULE:FREQ=DAILY This will generate dates like (generate 4 dates):

2021-01-01 09:00:00
2021-01-02 09:00:00
2021-01-03 09:00:00
2021-01-04 09:00:00

We can then save the iterator by changing it to DTSTART:20210104T090000\nRRULE:FREQ=DAILY If we then 'continue' the iterator (but this is a entirely new RRuleIter created from the string) to get more dates.

I think this can work in all cases. There are however a few more things we would have to change to.

  • Counter (COUNT) should also decremented.
  • The first date might overlap with the last day of the previous iteration, but this can easily be solved by just discarding an iteration.
  • It might create a new rrule that would return no result. (if counter is 0 or start date is after until date)
  • ...

I'm curious if there are things I'm not thinking of. This also requires a way of turning RRuleProperties back into a String. But this would be a nice feature anyway for stripping a rrule string from redundant data and making sure it is always valid.

Let me know what you all think.

ralpha avatar Oct 17 '21 22:10 ralpha

Interesting idea.

I guess you can store the last date generated and when you want to resume, just use skip_while until that date is surpassed. It is of course not as efficient as you need to regenerate all the old dates, but how big of a problem is that performance penalty anyways?

It might be quite tricky to store the state at a particular iteration as there are many moving parts, but definitely doable.

Do you have a specific use case in mind for this feature? Something you need in your own application? I would like to understand the need for the feature better :)

fmeringdal avatar Oct 18 '21 22:10 fmeringdal

I guess you can store the last date generated and when you want to resume, just use skip_while until that date is surpassed. It is of course not as efficient as you need to regenerate all the old dates, but how big of a problem is that performance penalty anyways?

This is not what I mean with the initial post, but this is how I'm going to do it for now.

Something you need in your own application?

Yes I want to use this in our application.

Do you have a specific use case in mind for this feature? [...] I would like to understand the need for the feature better :)

Let me explain the use-case in a bit more detail. We have a system where a user can define an interval for the creation of something on a recurring schedule. We thus use an RRule to define the interval. Lets day he want to create something daily. So every day the server will look at all the RRules that are stored and execute them up until the date of today and see if today is part of the list. Doing this is perfectly doable with the current implementation. But lets say this dossier has been going on for a year. So now every time it checks it has to go over 365 iterations before reaching the day of today. Doing this for a lot of RRules will quickly add up.

Now the solution to this I'm proposing is that we save the last created day found in the iteration, update the string dt_start to this day so the iteration will not start at 1 year ago, but just 1 day ago. This would thus safe us from needing to loop over 365 iterations and instead only 1-2 iterations might be needed.

The time interval (daily checks) is long enough that I don't just want to keep the RRule in memory until the next day. Also keeping things in memory does not scale well.

The library is fast enough and everything is not time critical enough that this is a major requirement in our case. But I see this can also be useful in other situations.

It might be quite tricky to store the state at a particular iteration as there are many moving parts, but definitely doable.

Yes, there are definitely things that might throw this technique off. But this is the reason I'm asking it here. If you or other people can see the faults in my assumptions. Are there things I'm forgetting or mistaken by?

Hope this makes it clearer.

ralpha avatar Oct 19 '21 13:10 ralpha