Home > Software design >  Calculating every third month with offset
Calculating every third month with offset

Time:08-19

I've been trying to figure out this algorithm for a couple days now. I may be lost in a loop in my thinking at this point - it seems like I'm overcomplicating the problem. I'm open to changing the approach, configuration records (or schema) or any other part of the algorithm.

Essentially, I want to perform an action (starting on a variable date) every x months (with optional offset) based on a set of configuration records. The configuration records look like this:

Start Offset Repeat
3 0
9 0
9 6

An explanation of these records:

  • Start 3, Repeat 0
    • Complete the action once three months from the start date
  • Start 9, Repeat 0
    • Complete the action once nine months from the start date
  • Start 9, Repeat 6
    • Complete the action every 6 months, skipping the first nine months

I've tried the following, but I don't get the output I expect. The results are close, but slightly off and I can't see why.

//start with an arbitrary date
var startDate = DateTime.Parse("2021-01-01");
//determine how many months we want to calculate for; in this case 5 years worth of time
var totalMonths =
    (
        DateTime.UtcNow.AddYears(5)
        .Subtract(startDate)
        .Days / 30
    )   1;

//get our configuration records
var configList = new List<ConfigItem>(){
    new ConfigItem(){StartOffset = 3, Repeat = 0},
    new ConfigItem(){StartOffset = 9, Repeat = 0},
    new ConfigItem(){StartOffset = 9, Repeat = 6},
}

for (var monthCount = 1; monthCount < totalMonths; monthCount  )
{
    //select the configs that apply to where we are in the count of months
    var configs = configList
    // this is a mess, just throwing stuff at the wall here
        .Where(tp =>
            (tp.StartOffset == monthCount && tp.RepeatMonths == 0)
            || (
                tp.RepeatMonths   tp.StartOffset <= monthCount
                && tp.RepeatMonths > 0
                && (
                    tp.RepeatMonths > 0
                    && (
                        (monthCount) % (tp.RepeatMonths)) == tp.StartOffset
                        || (monthCount) % (tp.RepeatMonths)==0
                    )
                )
        );

    foreach (var config in configs)
    {
        //do something
    }
}

Results: Everything seems right except the June (6) records - those shouldn't be there based on the configuration.

Date to do something
2022-09-15 2:18:14
2023-03-15 2:18:14
2024-03-15 2:18:14
2024-06-15 2:18:14
2025-03-15 2:18:14
2025-06-15 2:18:14
2026-03-15 2:18:14
2026-06-15 2:18:14
2027-03-15 2:18:14
2027-06-15 2:18:14

Thanks in advance!

CodePudding user response:

I think your solution would be less complicated if you used the configurations as a starting point instead of the months.

//start with an arbitrary date
    var startDate = DateTime.Parse("2021-01-01");

    //how far you want to calculate into the future
    var endDate = DateTime.UtcNow.AddYears(5);


    //get our configuration records
    var configList = new List<ConfigItem>(){
    new ConfigItem(){StartOffset = 3, Repeat = 0},
    new ConfigItem(){StartOffset = 9, Repeat = 0},
    new ConfigItem(){StartOffset = 9, Repeat = 6},
    };


    var listOfDatesToDoSomething = new List<DateTime>();

    foreach (var configItem in configList)
    {
        if (configItem.Repeat == 0)
        {
            if (startDate.AddMonths(configItem.StartOffset) <= endDate)
            {
                listOfDatesToDoSomething.Add(startDate.AddMonths(configItem.StartOffset));
            }
        }

        var date = startDate.AddMonths(configItem.Repeat);
        while (date < endDate)
        {
            listOfDatesToDoSomething.Add(date);
            date.AddMonths(configItem.Repeat);
        }
    }
  • Related