Computing Granular Patterns is CPU Intensive

Hello,

I’m using iCalendar to drive a process-scheduling component I’m developing. In many cases, I want processes to run on schedules such as “every friday” or “first of the month” and iCalendar works great for these. But in some cases, I need to run a process more frequently… for example: “every four hours on weekdays” or “every 15 minutes between 8am and 5pm”.

What I am observing is that the time to compute the “next” occurrence grows linearly with the number of occurrences since the start date. So, it seems the more frequent the recurrence pattern, the faster the growth.

As an example, computing the next occurrence for this pattern takes about 2.5 seconds:

DTSTART:20061101T010000

RRULE:FREQ=MINUTELY;INTERVAL=1

But, this one takes much much longer:

DTSTART:20051101T010000
RRULE:FREQ=MINUTELY;INTERVAL=1

Obviously, it seems like iCalendar always starts at the beginning of the pattern and computes all of the occurrences up to the next date. Is this how iCalendar always works, or is it possible to construct patterns that are computed more efficiently? For example, I wouldn’t think I need start at the beginning to compute this pattern: “Every 15 minutes on Weekdays between 8am and 5pm”.

If it is not possible for iCalendar to compute the next occurrence more efficiently, then are there any patterns that you would suggest to get around this limitation? As it stands, if I create a minutely schedule for a process. Within a year, my application will take hours to compute the next run time.

Hope my explanation is clear. Please let me know if you can offer any help.

Thanks,

Jake

One clarification… In the second-to-last paragraph, I ask if there are any patterns to get around the limitation. By “patterns”, I meant software design patterns, not recurrence patterns.

Hi Jake,

You observed correctly, the occurrences always have to be calculated from the beginning of the pattern.

I'm not a matematician to explain this properly, but an example is repeat every 2nd Tuesday cannot be calculated from any arbitrary date forward because you don't know whether the next Tuesday is "1st" and should be skipped or "2nd" and should be counted in. It can only be correctly calculated from the beginning of the pattern.

Maybe there are "simpler" patterns where an optimization could be used and occurrences calculated from any particular moment in time, but we don't have a developed theory on this.

You are also correct in noting that some patterns, especially when you come down to minutes or seconds become very heave in terms of occurrence numbers and calculating thousands of them every time is not convenient.

My personal point of view is that the iCalendar standard is a pretty limited and often awkward thing. I guess the problems you are experiencing can be attributed to the designers of the iCalendar standard thinking only of "human-specific" event, such as meetings, appointments etc and not giving a though to more frequent computer-related tasks such as batch processes etc.

The power of Aspose.iCalendar is in calculating complex patterns such as 2nd Monday of the Year, Last work day of a month and so on where you don't want to code such algorithms yourself. But when you talk about simple every 15 minute internal, it might pay ouf to actally just calculate those times yourself. You can also combine results from Aspose.iCalendar and your own. For example, use Aspose.iCalendar to calculate at least the day and maybe hour when you need to run the process, but use a simple loop to calculate minutes when you need to run it.

i am having the same problem myself and was thinking that the following idea could be the best optimization for the calculation: since you are intrested in scheduling tasks in the future, every week/moth/year or whatever other schedule, for each rule check for the last occurance and set that occurance as the start date of the rule.

roman, being the expert on this control, will this work?

i think that it will only work for singe rule patterns and not for complex patterns (if they can be created like skip 1 day, skip 2 days, skip 1 day, skip 2 days)

This seems like a major problem for me. I'm evaluating iCalendar for scheduling jobs that will run on "Secondly" patterns. If Aspose iCalendar always evaluates from the beginning of the pattern, then this will quickly cause a problem.

I've had to write my own recurrence engines before, and I'm observing from the outside, so I probably don't have all the facts, but shouldn't it be possible to skip over all the extra work mathematically?

As an example: I have a pattern that occurs once a minute, starting at midnight, January 1st, 2000. I should be able to mathematically determine the number of minutes from the pattern start date to the beginning of the evalutaion window, add that to the pattern StartDate, and skip all the instances in between, shouldn't I? I guess this wouldn't work well for patterns representing the next-to-last Tuesday of every third month, but then the brute force approach might not have as hard a time with those.