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.91k stars 257 forks source link

Advanced cron expressions #382

Open KaiserMarvin opened 7 months ago

KaiserMarvin commented 7 months 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 7 months 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 7 months 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.