Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Supporting a corner case, last day of a month #127

Open
yangyud-cn opened this issue Jul 8, 2024 · 3 comments
Open

Supporting a corner case, last day of a month #127

yangyud-cn opened this issue Jul 8, 2024 · 3 comments

Comments

@yangyud-cn
Copy link

It would be great if we could expand the cron expression to support one corner case, last day of a month.

https://stackoverflow.com/questions/6139189/cron-job-to-run-on-the-last-day-of-the-month

Also, instead of using "L" for it, an alternative is to use "0" for this special day, such that it works easier with the existing integer valued parser.

@atifaziz
Copy link
Owner

I'd like to avoid supporting extensions and corner cases if it can be helped unless someone helps to maintain and support those. That said, I think some extensions can be easily supported and built on top of NCrontab without changing the core implementation. I'm definitely planning to ship the feature developed in PR #37 that allows building occurrences out of multiple schedules. If you checkout that branch then something like L in your application could be done like so:

static IEnumerable<DateTime> EvaluateCrontabExpression(string expression, DateTime baseTime)
{
    if (expression.Split(' ', 5, StringSplitOptions.RemoveEmptyEntries)
        is not [var min, var hour, var day, var mon, var dow])
    {
        throw new FormatException("Invalid crontab expression.");
    }

    if (day.IndexOfAny(['L', 'l']) < 0) // short-circuit if no "L"
    {
        return CrontabSchedule.Parse(expression)
                              .GetNextOccurrences(baseTime, DateTime.MaxValue);
    }
    else
    {
        var days = day.Split(',', StringSplitOptions.TrimEntries).ToList();
        _ = days.RemoveAll(d => d is "L" or "l");

        // Schedule without "L"
        var schedule1 = CrontabSchedule.Parse(string.Join(' ', [min, hour, string.Join(",", days), mon, dow]));

        // Schedule with all possible "L" days
        var schedule2 = CrontabSchedule.Parse(string.Join(' ', [min, hour, "28-31", mon, dow]));

        // Prepare to combine the schedules
        var schedules = ImmutableArray.Create(schedule1, schedule2);

        return
            from e in schedules.GetNextOccurrences(baseTime, DateTime.MaxValue,
                                                   (s, dt) => (Schedule: s, Occurrence: dt))
            where e.Schedule == schedule1 // all of first schedule, or...
               || e.Occurrence.AddDays(1).Day == 1 // ...just where next day is 1st of next month
            select e.Occurrence;
    }
}

@stevehansen
Copy link

@atifaziz do you have an idea when a new version might be expected?

@atifaziz
Copy link
Owner

atifaziz commented Sep 8, 2024

@atifaziz do you have an idea when a new version might be expected?

@stevehansen If you're asking a general question, please post to the general discussions area.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants