Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to start a timer at a specific time for a specific time?

Tags:

c#

wpf

timer

Here is the scenario:

There is a Textbox in which a user enters the time at which the DispatcherTimer must start. The Timer is set to run for 4 hours always and Timer.Tick event plays a sound. Let's say the timer starts at 04:00:00 (HH:mm:ss), it should run till 8:00:00 and then stop. Then when the user changes the time, let's say, to 09:00:00. The timer should run till 13:00:00 and so on.

How can this be achieved? I can't run a 1 minute timer that keeps checking for the right time because that will be very heavy on the system.

All help is appreciated. Thank you in advance.

like image 503
thecodrr Avatar asked Jun 06 '16 11:06

thecodrr


People also ask

How do I get stopwatch on Google?

Just like with the timer, you can start a stopwatch right from Google's homepage. To do it, just type 'Start a stopwatch' in the search bar. Once it's running, you can start, stop, and restart the stopwatch.


2 Answers

The method below starts an initial timer with an interval based on the datetime supplied (i.e. the time entered into your textbox). When the the time is reached it starts a secondary timer that will fire every four hours from that point on.

I used System.Timers Timer rather than the Sytem.Threading Timer (because ironically the system.threading timer is not thread safe!)

    public void StartTimer(DateTime time)
    {
        const int fourHoursInMilliseconds = 4 * 3600 * 1000;

        var fourHourTimer = new Timer() {Interval = fourHoursInMilliseconds};
        fourHourTimer.Elapsed += (sender, e) =>
        {
            //code to handle the elapsed event here
        };

        var span = time - DateTime.Now;
        var timer = new Timer {Interval = span.TotalMilliseconds, AutoReset = false};
        timer.Elapsed += (sender, e) => { fourHourTimer.Start();};
        timer.Start();
    }

Hope this is what you need.

like image 138
mark_h Avatar answered Oct 21 '22 21:10

mark_h


You have 2 problems here.

  1. How to start the timer at specified time (this is called scheduling), see e.g. this.
  2. How to re-evaluate target time of possibly running timer.

Scheduling (assuming your software will be running) is basically creating timer when user finishes his input. If user changes time you have to stop that timer and start it again using new time.

Regarding re-evaluating, same tactic: create and start new timer every time user change value, taking in account whenever timer is running and already passed time.

So basically it will be 2 timers, where one is used to start another.

Pseudocode:

 DispatcherTimer _scheduler;
 DispatcherTimer _timer;
 DateTime _start;
 TimeSpan _duration;

 // call this when specified time is changed
 void Schedule(DateTime time)
 {
     _start = time;
     // prevent any logic to run if timer is counting duration
     if(_timer != null)
         return;
     // stop scheduler
     if(_scheduler != null)
         _scheduler.Stop();
     // create new scheduler
     _scheduler = new DispatcherTimer { Interval = _start - DateTime.Now };
     _scheduler.Tick = (s, e) =>
     {
         Start(_duration); // here scheduler will start timer
         _scheduler.Stop(); // after that you don't need scheduler anymore
         _scheduler = null;
     }
     _scheduler.Start();
 }

 // call this when duration is changed
 void Start(TimeSpan duration)
 {
     _duration = duration;
     // prevent from running before starting time
     if(DateTime.Now < _start)
         return;
     // stop running timer
     if(_timer != null)
         _timer.Stop();
     // create timer to count duration including already expired time
     _timer = new DispatcherTimer { Interval = _duration - (DateTime.Now - _start) };
     _timer.Tick = (s, e) =>
     {
         ... // whatever
         _timer.Stop(); // clean up
         _timer = null;
     }
     _timer.Start();
 }

I am using DispatcherTimer to avoid invoke when starting another DispatcherTimer. Both Schedule() and Start() should be called from UI thread (e.g. TextChanged event handler).

like image 1
Sinatr Avatar answered Oct 21 '22 20:10

Sinatr