0

Hello people of stackoverflow.I am having an issue when i try to take a time-span and convert it to a string.

Here is the code:

   private void timer1_Tick(object sender, EventArgs e)
    {
        timeLeft = timeLeft - 1;
        TimeLabel.Text = TimeSpan.FromMilliseconds(timeLeft).ToString("h'h 'm'm 's's'");
    }

Note that timeLeft is in milliseconds.

However whenever i try to pass this i get 2 sets of minutes sections. Like this: enter image description here

Although it should be this amount of time :

enter image description here

Gerard2202
  • 151
  • 6
  • 18
  • You should calculate the time left by subtracting two `DateTime` values, one of which would be `DateTime.Now`. You're not guaranteed the timer will tick correctly every time it is supposed to and might be skewed milliseconds either way, which over time will introduce inaccuracies in your time left. – Lasse V. Karlsen Sep 01 '14 at 13:43
  • Also, I don't understand what the problem is here. You're subtracting `1` from the value, and converting it through `FromMilliseconds`, obviously you're counting down one millisecond at a time. That will give you the shown value after 208 ticks. Is that not what you wanted? If not, then why did you do it that way then? – Lasse V. Karlsen Sep 01 '14 at 13:44
  • 56.792 is not 2 sets of minutes. Its 56 seconds and 792 miliseconds – Renatas M. Sep 01 '14 at 13:47
  • I don't understand what is the question? Can you explain it better? – Sriram Sakthivel Sep 01 '14 at 13:48

4 Answers4

2

I see you´re updating the label every timer ticks and although it´s not shown in the code it looks like your timer interval its set to 1 second probably, Am I right?.

The first thing you´re doing bad is trusting the 1 second interval you set up previously in your timer and hard-coding your code to that interval. The fact is you can´t rely in the timer interval to be precise because most of the timers have a awful resolution time of approximately 14 - 16 ms therefore that´s not a precise way to measure time.

You should use instead the time System.Diagnostics.Stopwatch class which uses the Win32 APIs QueryPerformanceFrequency and QueryPerformanceCounter. Those are the more reliable ways and fast ways to measure time due to the fact that Windows isn´t a Real Time Operation System.

As for how the code will look using I let a sample which should be pretty easy to adapt for you. Besides I include a solution for your TimeSpan - String translation trouble.

class Program
{
    static void Main(string[] args)
    {
        Stopwatch sw = new Stopwatch();

        Console.WriteLine("Starting..");
        sw.Start();
        Console.ReadLine();
        sw.Stop();
        Console.WriteLine("Elapsed time {0}:{1}:{2}:{3}", sw.Elapsed.Hours.ToString("00"), sw.Elapsed.Minutes.ToString("00"), sw.Elapsed.Seconds.ToString("00"), sw.Elapsed.Milliseconds);
    }
}

Be careful while using the System.Diagnostics.Stopwatch properties, there is a big difference in using the Elapsed.Ticks property and the ElapsedTicks property which it´s explained here.

Hope it helps!!

Community
  • 1
  • 1
nebtrx
  • 91
  • 1
  • 6
1

Due to the fact that there won't be any guarantee that the timer will be fired exactly every millisecond, you have to save a start time and then calculate the elapsed time by subtracting the start time from the current time.

Here is a code snippet to illustrate it:

private DateTime _StartTime;

private void OnCheckBoxTimerEnabledCheckedChanged(object sender, EventArgs e)
{
    _StartTime = DateTime.UtcNow;
    timer.Enabled = checkBoxTimerEnabled.Checked;
}

private void OnTimerTick(object sender, System.EventArgs e)
{
    var now = DateTime.UtcNow;
    labelTimeElapsed.Text = (now - _StartTime).ToString("h'h 'm'm 's's'");
}

In that case you also don't need to fire the timer every millisecond. Just fire it every 100ms to be accurate enough for the users eye.

And another tip: If you need to calculate relative times on your own you should always stick to DateTime.UtcNow and NOT DateTime.Now. So you won't get into trouble when your timer is running when you switch from normal time to summer time or vice versa.

Oliver
  • 43,366
  • 8
  • 94
  • 151
0

there is nothing wrong with your code. but i guess you Think there is since the above sample shows 2:02:56 and the other 02:03:00 wich is rather Close missing some 3200 milliseconds...

what is the actual value of timeLeft?

Read some more in the documentation on customizing timespan strings

Thorarins
  • 1,836
  • 16
  • 21
  • This is a shutdown timer to the value changes depending on the users input,in this instance it would be "3776000" it is calculated by this line `Settime = Convert.ToInt32(numericUpDown1.Value * 3600000 + numericUpDown2.Value * 60000 + numericUpDown3.Value * 1000);` – Gerard2202 Sep 01 '14 at 15:41
0

Using a Timer's Tick event to track passing time will result in inaccuracies as Lasse V. Karlsen mentioned in their comment on your question.

What you want to do is store a timestamp (DateTime.Now) when the timer begins, and compare that with a new DateTime.Now each time the timer ticks, like so:

    DateTime timestamp;
    TimeSpan timeLeft;

    private void begin_timer()
    {
        timestamp = DateTime.Now;
        timer1.start();
    }

    private void timer1_Tick(object sender, EventArgs e)
    {
        timeLeft = DateTime.Now - timestamp;
        TimeLabel.Text = timeLeft.ToString("HH:mm:ss.fff");
    }
Matt
  • 1,377
  • 2
  • 13
  • 26