Search code examples
c#timerwindows-services

Windows Service to run a function at specified time


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?


Solution

  • (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;