Windows Service to run a function at specified time

87,286

Solution 1

(1) On first start, Set _timer.Interval to the amount of milliseconds between the service start and schedule time. This sample set schedule time to 7:00 a.m. as _scheduleTime = DateTime.Today.AddDays(1).AddHours(7);

(2) On Timer_Elapsed, reset _timer.Interval to 24 hours (in milliseconds) if current interval is not 24 hours.

System.Timers.Timer _timer;
DateTime _scheduleTime; 

public WinService()
{
    InitializeComponent();
    _timer = new System.Timers.Timer();
    _scheduleTime = DateTime.Today.AddDays(1).AddHours(7); // Schedule to run once a day at 7:00 a.m.
}

protected override void OnStart(string[] args)
{           
    // For first time, set amount of seconds between current time and schedule time
    _timer.Enabled = true;
    _timer.Interval = _scheduleTime.Subtract(DateTime.Now).TotalSeconds * 1000;                                          
    _timer.Elapsed += new System.Timers.ElapsedEventHandler(Timer_Elapsed);
}

protected void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
    // 1. Process Schedule Task
    // ----------------------------------
    // Add code to Process your task here
    // ----------------------------------


    // 2. If tick for the first time, reset next run to every 24 hours
    if (_timer.Interval != 24 * 60 * 60 * 1000)
    {
        _timer.Interval = 24 * 60 * 60 * 1000;
    }  
}

Edit:

Sometimes people want to schedule the service to start at day 0, not tomorrow so they change DateTime.Today.AddDays(0).If they do that and set a time in the past it causes an error setting the Interval with a negative number.

//Test if its a time in the past and protect setting _timer.Interval with a negative number which causes an error.
double tillNextInterval = _scheduleTime.Subtract(DateTime.Now).TotalSeconds * 1000;
if (tillNextInterval < 0) tillNextInterval += new TimeSpan(24, 0, 0).TotalSeconds * 1000;
_timer.Interval = tillNextInterval;

Solution 2

Good answer (I used your code), but one problem with this line:

_timer.Interval = _scheduleTime.Subtract(DateTime.Now).TotalSeconds * 1000;

If DateTime.now is later than scheduleTime, you will go negative and this will generate an exception when assigning to timer.Interval.

I used:

if (DateTime.now > scheduleTime)
    scheduleTime = scheduleTime.AddHours(24);

Then do the subtraction.

Solution 3

Are you sure, you need a service, that runs only one time per day?

Maybe Windows Task Schedule will be better solution?

Solution 4

Use Windows built in Task Scheduler (http://windows.microsoft.com/en-us/windows7/schedule-a-task) or Quartz.net.

Unless ... you have a service that's doing lots of other processing and needs to be running all the time in which case a Timer might be appropriate.

Share:
87,286

Related videos on Youtube

Ziyad Ahmad
Author by

Ziyad Ahmad

Updated on April 23, 2021

Comments

  • Ziyad Ahmad
    Ziyad Ahmad about 3 years

    I wanted to start a Windows service to run a function everyday at specific time.

    What method i should consider to implement this? Timer or using threads?

  • Settapon H
    Settapon H over 10 years
    Instead of run timer every minutes, this timer will run once a day.
  • RacerNerd
    RacerNerd over 10 years
    It looks like you provided a nice code example. It would be helpful to add some explanation of the code around it to specifically address the question from the user.
  • MarceloBarbosa
    MarceloBarbosa almost 9 years
    Instead of making this a service, if you want it to run at a specific point in time, you could consider making it a normal console application, and running it with the Windows Task Scheduler
  • Mukus
    Mukus over 6 years
    I think if the task takes a long time to execute, it won't run exactly at 7 next time. It will keep growing.
  • Kiquenet
    Kiquenet about 6 years
    And run at 7:00 a.m to 21:00 pm interval each day Monday To Friday ? Not eastern-holidays
  • Kiquenet
    Kiquenet about 6 years
    any full sample using Quartz.net? AppDomain in Windows Service ? Console App?
  • C sharper
    C sharper over 5 years
    Instead of the " if (_timer.Interval != 24 * 60 * 60 * 1000) { _timer.Interval = 24 * 60 * 60 * 1000; } " - could be better to do _timer.Interval = (_scheduleTime - DateTime.Now).TotalMilliseconds that's way, it doesn't matter how long the function took, as long as it's less than 24 hours
  • fireshark519
    fireshark519 about 5 years
    in that case you should do while (DateTime.now > scheduleTime) { scheduleTime = scheduleTime.AddHours(24); } it just makes it better if it is more than just 1 day....it resolves any weirdness that may happen
  • Shehani Kalapuge
    Shehani Kalapuge over 3 years
    Is this task going to run at 7 am if someone restarts the service in the meantime?