How to make a 00:00 timer in c#? - c#

I'm just trying to make a basic mm:ss timer for a little sports scoreboard.
I currently have
int i = 0;
private void matchTimer_Tick(object sender, EventArgs e)
{
i++;
timeDisplay.Text = i.ToString("00:00");
}
But this fails because it doesn't account for minutes, so once time gets to 60, it just carries on
00:60
00:61
00:62
...
But I want it to be
01:00
01:01
01:02
...
and then stop at 80 minutes

You have more problems than you think. You're currently relying on the timer ticking exactly once per second. Don't do that - instead, use a System.Diagnostics.Stopwatch to measure the elapsed time, and then update the display by formatting the value of Stopwatch.Elapsed:
timeDisplay.Text = stopwatch.Elapsed.ToString("mm':'ss");
(See the Custom TimeSpan format strings documentation for more details.)

Timespan is made for that.
timeDisplay.Text = new TimeSpan(0, 0, i).ToString("mm\\:ss")

Your format string is incorrect. You should create a TimeSpan value and format that.

Related

Timer with TimeSpan and self-made timer are slower than Stopwatch

I'm trying to develop simple timer which can save its last value and continue from it at the new app start.
Stopwatch class is not serializable and even cannot be initialized in order to be started from specific time. But it works great. Benchmark showed that stopwatch's 1 minute is really 1 minute.
I tried to use TimeSpan in the following way:
private TimeSpan timerNew = new TimeSpan();
private DispatcherTimer dispatcherTimer = new DispatcherTimer();
public MainWindow()
{
InitializeComponent();
dispatcherTimer.Interval = TimeSpan.FromSeconds(1);
dispatcherTimer.Tick += Timer_Tick;
}
private void Timer_Tick(object sender, EventArgs e)
{
timerNew += new TimeSpan(0, 0, 0, 1);
TbTimer.Text = String.Format("{0:00}:{1:00}:{2:00}",
timerNew.Hours, timerNew.Minutes, timerNew.Seconds);
}
private void ButtonStart_OnClick(object sender, RoutedEventArgs e)
{
dispatcherTimer.Start();
}
private void ButtonStop_OnClick(object sender, RoutedEventArgs e)
{
dispatcherTimer.Stop();
}
private void ButtonReset_OnClick(object sender, RoutedEventArgs e)
{
timerNew = new TimeSpan();
TbTimer.Text = "00:00:00";
}
When I checked it against real stopwatch, I found out that this timer implementation lost 2 seconds per minute.
I also tried my own Timer implementation which is simple class with ulong field, which is incremented on each dispatcherTimer tick. And UI shows results after transformation of seconds to hours, minutes and so on. But it also loses 2 seconds per minute comparing to real stopwatch.
Why these 2 seconds are lost? What is an alternative to Stopwatch for usage in a customizable timer?
The Windows thread scheduler is not a "real-time" scheduler, as Windows is not a "real-time OS". In other words, all timing and scheduling is done on a "best effort" basis, without any guarantee of exact precision. In addition, this always results in lost time, because the one guarantee you do have is that scheduling will not happen early. So when there's an imprecision, it's always in the direction of "late".
The Stopwatch class works because it uses CPU-supported performance counters, which doesn't rely on the OS scheduler. The hardware itself tracks the elapsed time and provides the information you need.
I recommend against the use of DateTime.UtcNow for measuring elapsed time, for two reasons: first, the clock DateTime uses is adjustable, and so even using UTC time (which at least would compensate for automatic adjustments due to Daylight Saving Time) is not guaranteed to be accurate. Second, your specific scenario seems to involve an issue where you want to serialize the current state and restore it, which DateTime.UtcNow doesn't address anyway.
Instead, you should make your own serializable stopwatch class, which uses Stopwatch itself as the basis, but which stores a base elapsed value that you add to the Stopwatch's elapsed value.
For example:
class SerializableStopwatch
{
public TimeSpan BaseElapsed { get; set; }
public TimeSpan Elapsed { get { return _stopwatch.Elapsed + BaseElapsed; } }
private Stopwatch _stopwatch = new Stopwatch();
// add whatever other members you want/need from the Stopwatch class,
// simply delegating the operation to the _stopwatch member. For example:
public void Start() { _stopwatch.Start(); }
public void Stop() { _stopwatch.Stop(); }
// etc.
}
How exactly you would serialize the above is up to you. In the simplest scenario, you can just format the Elapsed property as a string to save the value, and then when you want to restore the object, parse that value, create a new instance of the above class, and then assign the value to the BaseElapsed property.
For additional discussion on the topic, you might find Eric Lippert's blog article Precision and accuracy of DateTime useful and interesting.

C# Time span to string issue

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:
Although it should be this amount of time :
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!!
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.
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
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");
}

How can i get the time of the pc in format of: hours,minutes,seconds,miliseconds?

private void timer1_Tick(object sender, EventArgs e)
{
Image mScreenImage = new Bitmap(Screen.PrimaryScreen.Bounds.Width,
Screen.PrimaryScreen.Bounds.Height);
ffmp.PushFrame((Bitmap)mScreenImage);
mScreenImage.Dispose();
}
I have this timer tick event with interval of 40ms.
I want to get each time the time clock time of the pc each 40ms.
for example if the time now is 1:00 AM so i want to see eavery 40ms:
1:00:00:40 then 1:00:00:80 and so on...
Beside this i want also to make a timer that will go forward and show me also each 40ms in the timer tick event.
00:00:00:40....00:00:00:80...
How can i do it in the timer tick event ?
Output the datetime using to string to format it.
var time = DateTime.Now.ToString("HH:mm:ss.ff");
This will replace h with hours, m with minuses s with seconds and f with fractions of a second (milliseconds). You can further change this format to suit your needs.
For more details see the MSDN documentation
Here is how to get the time:
string formatedTime = DateTime.Now.TimeOfDay.ToString("HH:mm:ss:ff");
You can use the DateTime.Now property with a format specifier:
DateTime.Now.ToString("HH:mm:ss:ff")
You have to set your timer
timer.Interval = 400;
And your timer tick event .. assumed in your label ..
void timer_Tick(object sender, EventArgs e)
{
label.Text = Label1.Text = Format(Now, "HH:mm:ss:ff");
}

How do I check how much time remains before timer fires next event?

For example, I have set timer1.Interval to 5000 and I would like to know how much of this interval remains before the timer ticks. How I can do it?
How to check timer time?
You cannot. The timer classes offer no way check how long remains before a timer is due to fire. The best you can do is to keep track of when the timer last fired and calculate yourself how long remains before the next tick.
DateTime MainTimer_last_Tick = DateTime.Now;
System.Windows.Forms.Timer timer_Calc_Remaining;
timer_Calc_Remaining.Enabled = true;
timer_Calc_Remaining.Interval = 100;
timer_Calc_Remaining.Tick += new System.EventHandler(this.timer_Calc_Remaining_Tick);
on main timer start or tick:
timer_Main.Enabled = true;
MainTimer_last_Tick = DateTime.Now;
private void timer_Calc_Remaining_Tick(object sender, EventArgs e)
{
int remaining_Milliseconds = (int)(MainTimer_last_Tick.AddMilliseconds(timer_Main.Interval).Subtract(DateTime.Now).TotalMilliseconds);
.../*
int newValue = (timer_Main.Interval -remaining_Milliseconds) ;
progressBar1.Maximum = timer_Main.Interval+1;
progressBar1.Value = newValue ;*/
}
You could use an alternative timer with an interval of 1000 (milliseconds). I don't think an interval of 1ms is really an option as this will stress the system too much and is unreliable anyway.
Every time this timer elapses, you can check the number of ticks (is this always a multitude of 1000?) and subtract it from (or use modulo) 5000.
But I can't:
That's because less than sign comes before equal sign and not the other way round
Its <= not =<
if (timer1.Interval <= 5000)
{
//do something
}
You are using the Interval which is a property that will not be getting changed (It will always be 5000, so checking if it is smaller than 5000 is pointless). Also, if this code is in the Timer1_Tick function it will not be efficient. However, the code I believe you need is:
if (timer1.Interval <= 5000)
{
//do something
}

getting program uptime

I'm beginner to programming. This is my code:
private void timer1_Tick(object sender, EventArgs e)
{
sec++;
textBoxSeconds.Text = sec.ToString();
if (sec > 59)
{
sec = 0;
textBoxSeconds.Text = sec.ToString();
min++;
textBoxMinutes.Text = min.ToString();
}
}
time goes too fast;/ and it stops for few sec sometimes. Hope someone can help me:)
*EDIT//*
thanks for help:) it works, but i still have a problem i didnt menton earlier. time stops sometimes for 1-2 sec, idk why. maybe because of some loops?
This is the wrong approach. When you program starts just save a DateTime instance, i.e. startTime. In your timer tick handler calculate the difference between the current time and the start time and display that.
private DateTime startTime = DateTime.Now;
private void timer1_Tick(object sender, EventArgs e)
{
var delta = DateTime.Now - startTime;
textBoxSeconds.Text = delta.Seconds.ToString("n0");
textBoxMinutes.Text = Math.Floor(delta.TotalMinutes).ToString("n0");
}
Using your code, I can say probably you haven't set the timer Interval, so:
timer1.Interval = 1000; //1000 ms = 1 second
Then you can improve something in the Tick event:
private void timer1_Tick(object sender, EventArgs e)
{
sec++;
if (sec == 60)
{
sec = 0;
min++;
}
textBoxSeconds.Text = sec.ToString();
textBoxMinutes.Text = min.ToString();
}
So use the DateTime class, it's the best solution.
EDIT:
DateTime startTime = DateTime.Now;
void timer1_Tick(object sender, EventArgs e)
{
TimeSpan time = DateTime.Now - startTime;
textBoxSeconds.Text = string.Format("{0:0#}", time.Seconds);
textBoxMinutes.Text = string.Format("{0:0#}", time.Minutes);
}
I agree about startTime - it is mandatory. I've also commented about DataTime.UtcNow - this is correct way.
About your second problem with 1..2 seconds lag - this is because timer's ticks racing side by side with seconds ticks.
1) If your timer will be triggered in 998ms instead of 1000ms, you can read the same amount of second and this number will stay before next tick.
2) Because application is not in real-time priority from OS point of view, it can be held for several seconds (e.g. for rendering multimedia stuff by other app) and you can notice a skip of 1 second...
To solve 1st reason and facilitate 2nd try to increase ticks count by decreasing Interval to 500 or 333.
For more advanced strategy that preserves your resources, you should still use 1000ms but synchronize you timer periodically with each half second crossing using dateTime.Milliseconds. That will maximize probability of avoiding side-by-side racing problem without extra ticks.

Categories