-2

I have a count down timer, when running it seems to get behind by 1 second every 5 - 10 seconds. Is there any way to make this countdown timer be accurate to system clock time?

Public MAIN()
            timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromMilliseconds(1000);
            timer.Tick += timer_Tick;



void timer_Tick(object sender, object e)
{
            basetime = basetime - 1;
            txt.Text = string.Format("{0:00}:{1:00}:{2:00}", basetime / 3600, (basetime / 60) % 60, basetime % 60);
            if (basetime == 0)
            {
                timer.Stop();
                Timer_Start.IsEnabled = Timer_Pause.IsEnabled = Timer_Restart.IsEnabled = true;
            }
}

i would love to try a few different ideas, also i will have to pause and start the timer periodically so will have to work that in to the solution as well.

matt vinck
  • 11
  • 4
  • 3
    Instead of keeping track of how many times `timer_Tick` has elapsed, just keep a `Stopwatch` which is started when you first start the timer, and then use *that* to find out how much time has actually elapsed. – Jon Skeet Apr 01 '19 at 18:16
  • Ok, do you have an example of how this will work? – matt vinck Apr 01 '19 at 18:17
  • Possible duplicate of [dispatcherTimer doesn't work accurately](https://stackoverflow.com/questions/23197993/dispatchertimer-doesnt-work-accurately) – Manfred Radlwimmer Apr 01 '19 at 18:17
  • 1
    Well, I've suggested using `Stopwatch`. I'd suggest looking into that type and what it provides, and trying to code it up yourself, then asking for concrete help after showing what you've tried. – Jon Skeet Apr 01 '19 at 18:18
  • Much appreciated ill look into that. – matt vinck Apr 01 '19 at 18:20
  • What you want to do is separate the calculation of the time from the display of the time. As @JonSkeet points out, a Stopwatch will allow you to find out how much time has elapsed. Then you just need something that periodically updates how that elapsed time is displayed. If you update the display every second, then every now and then, the display will appear to skip a second (for the similar reasons to what you are seeing). Consider updating the display every fraction of a second – Flydog57 Apr 01 '19 at 18:21

2 Answers2

0

Instead of trying to compute the time from an iterator, compute it using the system clock.

Change basetime's type to DateTime.

When you start the timer, set the base time: basetime = DateTime.Now; And set a TimeSpan variable to the amount of time to countdown: countdown = new TimeSpan(/*your code here*/);

Now update your timer_Tick like so:

void timer_Tick (object sender, object e)
{
    var now = DateTime.Now;

    // This computes the remaining time and formats it for display
    txt.Text = (now - basetime).ToString("hh:mm:ss");

    // Checks that the timer is complete
    if (now - basetime > countdown)
    {
        /* stop the timer */
    }
}

DispatcherTimer isn't perfectly accurate, it is approximate, which for most tasks is good enough, but for keeping track of time is inadequate. Instead you may use it to approximate a second, and then update your timer with the actual time from the system clock.

  • 1
    I'd strongly recommend the use of either `Stopwatch` which is more directly designed for being measuring elapsed time (and can be easily stopped and started) or *at least* using `DateTime.UtcNow` instead of `DateTime.Now`, to avoid things getting pretty weird if the code is running across a time zone transition. – Jon Skeet Apr 01 '19 at 19:10
0

Solution;

Run a stop watch and compare the math to it.

P.S. I know there is better ways of doing this and may update in future releases.


        void Timer_Tick(object sender, object e)
         {
            int BaseINMill = basetime * 1000;
            //total of milliseconds left
            basetimeMILL.Text = BaseINMill.ToString() ;
            //Display the total Milliseconds elapsed
            ConsolePost.Text = VerifyMill.ElapsedMilliseconds.ToString();


            if( CorrectionWatch.ElapsedMilliseconds >= 2000)
            {
                PreCorrBaseTime = PreCorrBaseTime - 2;

                //Display the Correction timer Milliseconds elapsed
                Correctiontest.Text = CorrectionWatch.ElapsedMilliseconds.ToString();
                CorrectionWatch.Restart();
                //Show the total time between seconds changing on screen
                ConsoleOutputPre.Text = stopwatch.ElapsedMilliseconds.ToString();
                basetime = PreCorrBaseTime;
                txt.Text = string.Format("{0:00}:{1:00}:{2:00}", basetime / 3600, (basetime / 60) % 60, basetime % 60);
                if (basetime == 0)
                {
                    timer.Stop();
                    Timer_Start.IsEnabled = Timer_Pause.IsEnabled = Timer_Restart.IsEnabled = true;
                    VerifyMill.Stop();
                }
                stopwatch = Stopwatch.StartNew();
            }
            else {
                if (stopwatch.ElapsedMilliseconds >= 975 && stopwatch.ElapsedMilliseconds <=1025 )
                {
                    //Show the total time between seconds changing on screen
                    ConsoleOutputPre.Text = stopwatch.ElapsedMilliseconds.ToString();
                    basetime = basetime - 1;
                    txt.Text = string.Format("{0:00}:{1:00}:{2:00}", basetime / 3600, (basetime / 60) % 60, basetime % 60);
                    if (basetime == 0)
                    {
                        timer.Stop();
                        Timer_Start.IsEnabled = Timer_Pause.IsEnabled = Timer_Restart.IsEnabled = true;
                        VerifyMill.Stop();
                    }
                    stopwatch = Stopwatch.StartNew();
                }

                if (stopwatch.ElapsedMilliseconds >= 1026 && stopwatch.ElapsedMilliseconds <= 2000)
                {
                    //Show the total time between seconds changing on screen
                    ConsoleOutputPre.Text = stopwatch.ElapsedMilliseconds.ToString();
                    basetime = basetime - 1;
                    txt.Text = string.Format("{0:00}:{1:00}:{2:00}", basetime / 3600, (basetime / 60) % 60, basetime % 60);
                    if (basetime == 0)
                    {
                        timer.Stop();
                        Timer_Start.IsEnabled = Timer_Pause.IsEnabled = Timer_Restart.IsEnabled = true;
                        VerifyMill.Stop();
                    }
                    stopwatch = Stopwatch.StartNew();
                }
                if (stopwatch.ElapsedMilliseconds > 2000)
                {
                    ErrorPrompt();
                    VerifyMill.Stop();
                }
            }


        }
matt vinck
  • 11
  • 4