Marcel De Villiers
Marcel De Villiers

Reputation: 1812

Make a timer fire at the end of each month c#

I need to make a timer fire at the end of each month. I have written a small program that has code that needs to be executed at the last day of each month and I have no idea how to implement it. I suggested to my boss using windows scheduler but he wants it done in code with timer.

So how do I do this ?

Upvotes: 1

Views: 4039

Answers (2)

Adebayo S
Adebayo S

Reputation: 1

Here's a simpler way to get your job to run only on the last day of the month.

// Set timer to run every 24hrs
new Timer(RunJobMethod, null, 0, (int)TimeSpan.FromHours(24).TotalMilliseconds);

Add the below piece of code to your RunJobMethod

// Enforce it only runs on the last day of the month
var currentMonth = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1);
var nextMonth = currentMonth.AddMonths(1);
var lastDay = nextMonth.AddDays(-1);
if (DateTime.Now.Day != lastDay.Day || DateTime.Now.Month != lastDay.Month || DateTime.Now.Year != lastDay.Year)
    return;

Upvotes: 0

Marcel De Villiers
Marcel De Villiers

Reputation: 1812

I managed to persuade the boss to use windows scheduled tasks. There is a way to do this with a timer. I include the code here below. It is quick and dirty. Note strongly that Using Scheduled tasks IS the correct way to implement this kind of task.

    private Timer timer;

    public MyClass()
    {
        timer = new Timer();
        timer.Elapsed += TimerElapsed;
    }

    private void TimerElapsed(object sender, ElapsedEventArgs elapsedEventArgs)
    {

        if (DateTime.Now.Day == DateTime.DaysInMonth(DateTime.Now.Year, DateTime.Now.Month))// is it the last day of this month
        {
            ClientStatsController.FireAll();
        }

        Thread.Sleep(TimeSpan.FromMinutes(5));
        timer.Interval = CalculateInterval();
        TimeSpan interval = new TimeSpan(0, 0, 0, 0, (int)timer.Interval);

    }

    // Helper functions
    private static TimeSpan From24HourFormat(string value)
    {
        int hours = Convert.ToInt32(value.Substring(0, 2));
        int mins = Convert.ToInt32(value.Substring(2, 2));

        return TimeSpan.FromHours(hours) + TimeSpan.FromMinutes(mins);
    }

    private double CalculateInterval()
    {
        string runtimeValue = ConfigController.AppSettings["runTime"]; // just a simple runtime string like 0800
        double runTime = From24HourFormat(runtimeValue).TotalMilliseconds;
        if (DateTime.Now.TimeOfDay.TotalMilliseconds < runTime)
        {
            return runTime - DateTime.Now.TimeOfDay.TotalMilliseconds;
        }
        else
        {
            return (From24HourFormat("2359").TotalMilliseconds - DateTime.Now.TimeOfDay.TotalMilliseconds) + runTime;
        }
    }

EDIT

I started going through all my older questions and answers.

Using a timer is a very bad idea. For scheduled tasks you want to use exaclty that. A scheduler. Windows provides a decent task scheduler, but if you have more complex scheduling logic and background tasks, it is better to use a proper third party library.

The two outstanding ones for .NET are Hangfire and Quartz.

Hangfire comes complete with a dashboard and is super easy to implement, especially if your working on the .NET core platform.

Quartz is also a very nice solution, and it has more scheduling options and better suited for complicated scheduling logic than Hangfire.

The proposed solution is indeed a very bad on, coming from an intern who just started working. I am happy to go back in time and realize how things can be done differently and better.

Upvotes: 1

Related Questions