jamesmh / coravel

Near-zero config .NET library that makes advanced application features like Task Scheduling, Caching, Queuing, Event Broadcasting, and more a breeze!
https://docs.coravel.net/Installation/
MIT License
3.59k stars 240 forks source link

Advanced cron expressions #382

Open KaiserMarvin opened 4 weeks ago

KaiserMarvin commented 4 weeks ago

I would like to run the task on the last day of the month or more specifically on the last working day of the month at 6pm. This would work with the following cron expression "0 18 LW " unfortunately this is not supported by Coravel. Would it be possible to extend the parser for these cron expressions to allow the usage of the commands L, W, ? and #, as it is the case in Hangfire, for example (https://github.com/HangfireIO/Cronos) ?

ivoloshin commented 3 weeks ago

You can probably do something like below. I assume it'll check daily at 6PM, and then run the predicate to check if it should run on that day.


scheduler.Schedule<MyJob>()
  .DailyAtHour(18)
  .When(IsLastWorkingDayOfMonth);

//compliments of ChatGPT with some mods
public async Task<bool> IsLastWorkingDayOfMonth()
{
    Func<DateTime, DateTime> GetLastWorkingDayOfMonth = date =>
    {
        DateTime lastDayOfMonth = new DateTime(date.Year, date.Month, DateTime.DaysInMonth(date.Year, date.Month));

        // Check if the last day of the month falls on a weekend
        if (lastDayOfMonth.DayOfWeek == DayOfWeek.Saturday)
        {
            return lastDayOfMonth.AddDays(-1); // If it's Saturday, return the previous Friday
        }
        else if (lastDayOfMonth.DayOfWeek == DayOfWeek.Sunday)
        {
            return lastDayOfMonth.AddDays(-2); // If it's Sunday, return the previous Friday
        }
        else
        {
            return lastDayOfMonth; // If it's a weekday, return the last day of the month
        }
    };

    DateTime today = DateTime.Today;
    DateTime lastWorkingDay = GetLastWorkingDayOfMonth(today);

    return lastWorkingDay == today;
}
KaiserMarvin commented 3 weeks ago

@ivoloshin thank you for the quick answer. For me, I actually solved it simply by running the job daily as from you suggested and using the already mentioned Cronos library (https://github.com/HangfireIO/Cronos) in the When function. For the future, however, it would of course be nice if Coravel itselfs supports the full cron expression scope natively.