I stumbled over an interesting codeunit in Business Central to help calculate recurrences. Check out the video:

In this video, Erik explores a hidden gem in the Business Central System App: the Recurrence Schedule module. While browsing the system application code, he stumbled upon this module and initially thought it was about event-driven scheduling. In reality, it’s a utility for calculating recurring dates — daily, weekly, monthly, and yearly — offering an alternative to the well-known CalcDate function.
What Is the Recurrence Schedule Module?
Business Central has several features that rely on recurrence calculations: deferral schedules, recurring journals, and more. Traditionally, developers have reached for the CalcDate function, which takes a date formula and adds it to a starting date. It’s simple and effective for many scenarios.
However, Microsoft has introduced the Recurrence Schedule codeunit in the System App, which provides a more structured way to define and calculate recurrences. The module’s description says it provides “methods for scheduling the recurrence of an event,” but really it’s about calculating when the next occurrence of a recurring pattern falls.
Setting Up a Test Environment
Erik sets up a simple table and page to experiment with the module. He creates a basic table called “My Dates” with a start date field, along with a corresponding list page. He uses the ASet AL snippets (created by Andris) to quickly scaffold both objects.
On the page, he adds a promoted action called “Test” where all the experimentation happens. With Business Central version 21+, he uses the newer action reference syntax for promoted actions rather than the older Promoted property approach.
Working with the Recurrence Schedule Codeunit
The Recurrence Schedule codeunit (named recur in the demo) offers several key methods:
- SetMinimumDateTime — Sets the earliest date to return from
CalculateNextOccurrence - CreateDaily — Creates a daily recurrence pattern
- CreateWeekly — Creates a weekly recurrence with specific days of the week
- CreateMonthly — Creates a monthly recurrence
- CreateMonthlyByDayOfWeek — Creates a monthly recurrence based on day of week
- CreateYearly — Creates a yearly recurrence
- CalculateNextOccurrence — Returns the next DateTime based on the recurrence and the last occurrence
- RecurrenceDisplayText — Returns a short text description of the recurrence
Weekly Recurrence Example
Erik’s first experiment is with CreateWeekly. The method takes several parameters: start time, start date, end date, weeks between occurrences, and then a boolean for each day of the week (Monday through Sunday). He sets up a recurrence for every Monday and Thursday:
recur.SetMinimumDateTime(CurrentDateTime());
recur.CreateWeekly(
0T, // Start time
Today(), // Start date
20231231D, // End date
1, // Every 1 week (not 2!)
true, // Monday
false, // Tuesday
false, // Wednesday
true, // Thursday
false, // Friday
false, // Saturday
false // Sunday
);
Initially, Erik set the “weeks between” parameter to 2, which caused the results to skip weeks. After checking the documentation and realizing his mistake, he corrected it to 1, and the results perfectly matched his Monday/Thursday video recording schedule.
To iterate through the occurrences, he uses a loop:
for i := 1 to 10 do begin
lastDate := recur.CalculateNextOccurrence(ID, lastDate);
rec."Start Date" := DT2Date(lastDate);
rec.Insert();
end;
Daily Recurrence Example
He also tests the daily recurrence with a three-day interval:
recur.CreateDaily(
0T, // Start time
Today(), // Start date
20231231D, // End date
3 // Every 3 days
);
This produces predictable results — every three days from the start date. As Erik notes, this is essentially “a fancy wrapper for CalcDate,” since you could achieve the same result with a simple CalcDate('3D', StartDate).
When Does It Really Shine?
The real power of the Recurrence Schedule module becomes apparent with the weekly recurrence. Calculating “every Monday and Thursday” with CalcDate would require significantly more custom logic — you’d need to figure out which day of the week you’re on, calculate the gap to the next target day, and handle week boundaries. The Recurrence Schedule module handles all of this cleanly.
Edge Cases and Observations
What Happens When Dates Run Out?
Erik tests what happens when CalculateNextOccurrence runs past the end date. The result: it simply returns the same date as the last valid occurrence. This means you need to track the previous value and compare to detect when the recurrence has exhausted its range.
The RecurrenceDisplayText Method
Erik also tries the RecurrenceDisplayText method, hoping for a detailed description. Unfortunately, it only returns something like “Recurring Weekly” — it doesn’t specify which days are selected. Not as informative as one might hope.
The CalcTime Bonus: Duration Arithmetic in AL
The source code in the project also contains an interesting CalcTime procedure that Erik had been working on separately. While CalcDate handles date arithmetic with date formulas, there’s no built-in equivalent for time arithmetic in AL. This custom implementation parses a time expression string (like '1W4H' for one week and four hours) and applies it to either a DateTime or Time value:
procedure CalcTime(TimeExpression: Text; StartDateTime: DateTime): DateTime
var
i: Integer;
Op: Text;
OpInt: Integer;
ExpressionDuration: Duration;
begin
for i := 1 to strlen(TimeExpression) do begin
if IsChar(TimeExpression[i]) then begin
Evaluate(OpInt, Op);
case TimeExpression[i] of
'W':
ExpressionDuration += OpInt * 7 * 24 * 60 * 60 * 1000;
'D':
ExpressionDuration += OpInt * 24 * 60 * 60 * 1000;
'H':
ExpressionDuration += OpInt * 60 * 60 * 1000;
'M':
ExpressionDuration += OpInt * 60 * 1000;
'S':
ExpressionDuration += OpInt * 1000;
end;
Op := '';
end else
Op += TimeExpression[i];
end;
exit(StartDateTime + ExpressionDuration);
end;
This procedure supports weeks (W), days (D), hours (H), minutes (M), and seconds (S) in the expression. It converts everything to milliseconds (the unit used by AL’s Duration type) and adds it to the starting DateTime. There’s also an overload that works with Time values and wraps around midnight using the modulo operator.
Summary
The Recurrence Schedule codeunit in the Business Central System App is a useful alternative to CalcDate when you need more complex recurrence patterns — particularly weekly schedules with specific days of the week. For simple interval-based recurrence (every N days), CalcDate remains perfectly adequate. But when you need to express something like “every Monday and Thursday” or “the second Tuesday of each month,” the Recurrence Schedule module saves you from writing that logic yourself.
Key takeaways:
- The module lives in the System App and is available from the
Recurrence Schedulecodeunit - It works with
DateTimevalues, not plainDate— useDT2Dateto convert - Pay attention to the “between” parameters — setting weeks between to 1 means every week, 2 means every other week
- When the recurrence runs out of dates,
CalculateNextOccurrencereturns the last valid date rather than an empty value - The
RecurrenceDisplayTextgives only a generic description, not a detailed one