0

I have an invocable that I plan to use that can help let a flow user choose to execute a process only every other week based on their inputs of "Current Day of the Week" (string), and a Start Date.

So if someone were to input 'Monday' and choose a start date of 5/1/2024, then the next time the flow element should return true would be when the flow runs on 5/15/2024.

I have 1 method that should get the next occurrence of a specified day of the week:

// Helper method to find the next occurrence of the specified day of the week
@TestVisible
private static Date getNextDayOfWeek(Date fromDate, String dayOfWeek) {
    
    Integer targetDay = getDayOfWeekAsInteger(dayOfWeek);
    
    DateTime dateTimeVar = DateTime.newInstance(fromDate.year(), fromDate.month(), fromDate.day());
    
    Integer currentDay = Integer.valueOf(dateTimeVar.format('u')); // 'u' gives the digit day of the week
    
    Integer daysToAdd = targetDay - currentDay;

    if (daysToAdd < 0) {
        daysToAdd += 7;
    }

    return fromDate.addDays(daysToAdd);
}

And another helper method to try and calculate the next run date:

// Helper method to calculate the next run date based on start date and day of the week
public static Date calculateNextRunDate(Date startDate, String dayOfWeek, Date today) {
    Date nextDayOfWeek = getNextDayOfWeek(today, dayOfWeek);

    // Calculate days between start date and next occurrence of the target day
    Integer daysBetween = startDate.daysBetween(nextDayOfWeek);

    
    // Adjust the next run date to ensure it's on a bi-weekly schedule
    
    while (Math.mod(daysBetween, 14) != 0) {
        nextDayOfWeek = nextDayOfWeek.addDays(7);
        daysBetween = startDate.daysBetween(nextDayOfWeek);
    }
    
    

    return nextDayOfWeek;
    
}

The problem is using Math.mod in a loop like that causes Apex cpu limits.

Is there an easier approach to this using Apex (or any other method)?

1
  • 2
    Unless I'm missing something here, the issue isn't so much that you're using Math.mod() in a loop, but more that you have an infinite loop. If daysBetween is not a multiple of 7, you'd never get to a multiple of 14 by adding 7. Might be worthwhile to set up a counter and a debug to see just how many times your loop is running.
    – Derek F
    Commented May 31 at 18:18

1 Answer 1

0

As I said in my comment, the issue here is actually that you have an infinite loop.

If you pass in a startDate that isn't the same day of the week that you pass in for dayOfWeek, then daysBetween will not be a multiple of 7. Because of that, and because you only ever add 7 days in your loop, you'll never get out of the loop.

The quick fix here would be to call getNextDayOfWeek(startDate, dayOfWeek);, store that as a new variable, then use that instead of startDate when you call daysBetween().

public static Date calculateNextRunDate(Date startDate, String dayOfWeek, Date today) {
    Date nextDayOfWeek = getNextDayOfWeek(today, dayOfWeek);

    // If startDate isn't on the target day of the week, it'd lead to an infinite loop
    // Call getNextDayOfWeek() to ensure that doesn't happen
    Date nextStartDate = getNextDayOfWeek(startDate, dayOfWeek);

    // Need to use nextStartDate here to avoid the infinite loop (if we were
    //   still using a loop)
    Integer daysBetween = nextStartDate.daysBetween(nextDayOfWeek);

    // Now that we know that nextStartDate and nextDayOfWeek are both on the same day of
    //   the week, they're either a multiple of 7 or 14 days apart
    // So the most we'll need to do is add 7 days one time.
    // I.e. this loop can become an if (or a ternary)
    //while (Math.mod(daysBetween, 14) != 0) {
    if(Math.mod(daysBetween, 14) != 0) {
        nextDayOfWeek = nextDayOfWeek.addDays(7);

        // Need to use nextStartDate here to avoid the infinite loop (if we were
        //   still using a loop)
        //daysBetween = nextStartDate.daysBetween(nextDayOfWeek);
    }
    
    return nextDayOfWeek;
}

Some other notes for other people looking at this:

DateTime dateTimeVar = fromDate runs into some timezone auto-conversion issues (being one day in the past for people in UTC -X:XX timezones), and DateTime dateTimeVar = DateTime.newInstance(fromDate.year(), fromDate.month(), fromDate.day()) avoids those issues.

Using dateTimeVar.format('u') sidesteps the issue of some countries using Sunday as the start of the week and others using Monday as the start of the week

1
  • thinking a little more on this, since calling getNextDayOfWeek() on startDate ensures that Math.mod(daysBetween, 14) will always return 0 or 7, we can eliminate the loop/if/ternary entirely. nextDayOfWeek = nextDayOfWeek.addDays(Math.mod(daysBetween, 14)); will always do the right thing (at the cost of being a bit less readable).
    – Derek F
    Commented Jun 3 at 18:49

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .