How to make an accurate decimal Timer? - c#

I'm pretty frustrated about this one ..
I have a timer called timer1 and a text box called TimeElapsedTextBox and a double variable called TimeTakenToFinish
the timer ticks every 1 second (1000 millisecond)
in the text box, I want it to display the time in this format:
Seconds.PartsOfSecond
Here is the Tick event:
private void timer1_Tick(object sender, EventArgs e)
{
TimeTakenToFinish += (double)timer1.Interval / 10000;
TimeElapsedTextBox.Text = TimeTakenToFinish;
}
it is actually displaying it in the text box the way i want it,
but it's not counting properly ..
I mean, it's counting less than a real second..
could you please tell me how to fix this ..

Your problem here is a misunderstanding of the way your OS works. Sure, you can set the interval to 1000ms, but you cannot expect it to actually tick every second. You are running code on Windows, not a hard (or soft) real time operating system.
As an aside, you should also know that the resolution of your timer is finite, and as of today, limited to the accuracy of your system timer, which is probably about 15ms.
You cannot expect your code to perform that deterministically in that sort of environment. At any point the OS can preemptively kick you out of the CPU and start working on another task.
You simply cannot get the accuracy you desire, though I would ask; is it actually required? Probably not, but you haven't told us what you are actually trying to accomplish here, so who knows?
Also, this is wrong:
TimeTakenToFinish += (double)timer1.Interval / 10000;
Interval is a property which is used to tell the timer roughly how often it should fire the Tick event. You are not actually measuring anything, you may as well just be adding 1000.0 / 10000 to your counter every time.
If you need more precision use the StopWatch class which uses your CPU's high performance timer if available. You can still use a timer to periodically update the UI based on the current elapsed value of the Stopwatch, i.e.,
void timer1_Tick(...)
{
var totalSeconds = _someStopwatch.ElapsedMilliseconds / 1000.0;
TimeElapsedTextBox.Text = totalSeconds.ToString();
}

Instead of using a timer, record the start time using DateTime.Now and then subtract the current time (DateTime.Now) from the start time. This will give you a more accurate timer as it uses the system clock instead which isn't affected so much by CPU performance.
Alternatively you can use System.Diagnostics.Stopwatch which does this for you.
You can still use an ordinary timer with an interval of less than a second to refresh the label displaying the time.

Related

How to make timer fire in a recurring manner

I have a timer which I want to expire every Monday at 5pm. When testing the application, as soon as it reaches 5pm on a Monday, my task is fired as it is supposed to.
However, when I change the system date and time to the following week at 5pm, the task does not fire. This is my code:
Timer timer = new Timer(callback, application, timeToEnd, TimeSpan.FromDays(7));
I have a feeling that it has something to do with the TimeSpan.FromDays(7) part. Any ideas?
This is not a good use for a Timer. You should create a console application that does what you want, then schedule it with Windows Scheduler or a 3rd party scheduling tool.
Otherwise, the safer thing to do is to set the timer to run at a short interval (1 minute?) and check the system clock to see if it needs to run or not (e.g. is it within 1 minute of 5:00?)
You're now in trouble. We asked the framework to notify you after x days, y hours, z minutes. So timer will fire exactly after what time you told it to.
I know this is not the right way to go, but this will work.
SystemEvents.TimeChanged += SystemEvents_TimeChanged;
static void SystemEvents_TimeChanged(object sender, EventArgs e)
{
timer.Dispose();//Dispose your previous timer
SetTimerAgain();//Call the method which sets the timer again. you're done
}
I recommend "Windows Scheduled Tasks", but for some reason you can't so here is the way to go.
Also you could run a periodic timer as #giammin suggested.
TimerCallback callback = (state) =>
{
var now = DateTime.Now;
if(now.DayOfWeek == DayOfWeek.Monday
&& now.TimeOfDay.Hours == 17 && now.TimeOfDay.Minutes == 0)
{
MyMethod();
}
};
Timer timer = new Timer(callback, application, 0, 10000);//10seconds
With the latter approach you should defend yourself from calling the method again and again for the same day.
None of the timers depend on the system time.
Changing the clock will not affect System.Windows.Forms.Timer, System.Timers.Timer, or System.Threading.Timer.
If you need to handle those situation you have to rely on SystemEvents.TimeChanged
Otherwise you can check periodically for DateTime.Now.DayOfWeek == DayOfWeek .Monday
If you do not want to rely on an external service like the Window Task Scheduler you will have to create a timer that fires at regular intervals (say every minute) and checks the current time, and if the current time has passed the next expiration time it actually performs the desired action (including setting up the next expiration time).
Performing a time check every minute should not be a problem unless you are running on a low powered device.
Moving the clock forward a week is a pretty extreme measure but daylight savings can also move the clock and in particular on virtual machines you may have some unexpected clock drift. This is why checking the current time at regular intervals most of the time is better than just setting a timer to fire at some distant future time.
Speaking of daylight savings you need to handle the situation where the clock moves backward one hour in case your want to perform you activity in that interval.
If you want a timer that will fire at a specific time, use a Waitable Timer. Unfortunately, the .NET libraries don't have a wrapper for that timer. I wrote one some time back for an article. The article is no longer available online, but you can download the source code from http://mischel.com/pubs/waitabletimer.zip.
That said, it sounds to me what you have is a catnap program. Do as others have suggested and make it a simple console app that you control with Scheduled Tasks.

Precise timer with event similar to Timer.Tick

I am doing a simple high score add-in for a game. For this, I need a precise timer from which I can display the elapsed time in a Label. I have so far tried the following:
Windows.Forms.Timer: does not keep high resolution intervals, some are slower, some are faster.
System.Diagnostics.Stopwatch: no tick event.
I also thought of implementing a low-resolution Forms.Timer. Then, when the timer starts and stops I would store the system time and just subtract them to get the elapsed time. But I don't want to over-complicate things. Any ideas?
I don't think it would be overcomplicated to use a combination of a Stopwatch (for its high resolution) and the low-resolution Windows.Forms.Timer.
The Stopwatch is extremely straightforward to use, so it adds very little complexity to using a Timer too.
(This assumes you are ok with high-resolution elapsed time display but with a lower-resolution update interval.)
Use elapsed time since some moment. Than either:
Pick any timer, set it for 15ms and display elapsed time on each tick (should be ok if you are dealing with WinForm/WPF controls)
On every frame refresh display new value (if your code get notified/invoked on every frame refresh)
If you're willing to take the dependency, you could use Reactive Extensions (Rx) to get a timer:
var timer = Observable.Interval(TimeSpan.FromMilliseconds(15))
.Subscribe(() => /* handler */ );
Rx will make sure that the handler is called on the same thread the subscription was created on, and under the covers it uses System.Threading.Timer so it has pretty high and consistent resolution.

C# High accuracy Timing

I am making a small typing test in C# in which the program asks you to type a word and then shows you your time.
I was using the c# timer class (drag and drop a timer from the toolbox), with a Tick time of 1ms, however it wasn't giving me accurate results, so I substituted it for a StopWatch , so now the timing is super accurate, but the problem is that it seems that you cannot assign event handlers to a StopWatch so although I can show the user his time when he FINISHES the word, I cannot actually show hum the time WHILE he is typing.
Thoughts?
Use a StopWatch to accurately measure time; and use a Timer to periodically fire a UI update, displaying the time measured by the StopWatch. For UI, you don't need 1 ms resolution (The screen update time is likely to be larger than 1 ms, and, the human eye won't be able to perceive updates that fast anyways).
Try having updates each 40 - 100 ms, I think that will be adequate.
Use another Timer that fires events every 10th of a second or so and polls for the Stopwatch value. It won't be nearly as accurate as the Stopwatch since there will be a lag but humans can't really react to anything faster than a 10th of a second.
Use the System.Timers.Stopwatch class, and check if high resolution is available by checking the field IsHighResolution (System.Timers.Stopwatch.IsHighResolution == true).
Then, whenever you need something fired, fire it through another timer at the lowest interval possible, which checks the value of your Stopwatch. Though this won't be perfect (you don't even need close to perfect), it'll work.

Timer speed Problem WPF

I am using timer to scroll the list. Every millisecond interval i am initiating the Tick event. Event though the animation looks very slow.
repeatTimer_Tick(this, new EventArgs());
repeatLeftTimer.Interval = TimeSpan.FromMilliseconds(1);
repeatLeftTimer.Tick += new EventHandler(repeatTimer_Tick);
The timers in windows have a resolution of several milliseconds, IIRC, something between 10 and 50 ms. You can't get the normal timer to tick every millisecond.
I would try to use an animation for what you're doing.
The .NET timer classes generally have a minimum interval of 15.6 ms. If you need a faster increment (down to 1ms) Windows provides a multimedia timer in the unmanaged API. You could import this timer and use it -- I've done it and it works.
I based my code off of this: http://www.codeproject.com/KB/miscctrl/lescsmultimediatimer.aspx
Should be most of what you need; I added some code to look at the high resolution timer and observe the time between ticks -- I was able to get it to 1ms, += 0.10 ms
You have two good and (relatively) easy options:
Use an animation - WPF has a very versatile animation system that is likely to be able to do what you need.
Use the CompositionTarget.Rendering Event, those are called as fast as possible (each frame) and you are responsible in each call to set the current status based on the current time (that is how the built in animations work)
If you need a high resolution then I would suggest looking into the Stopwatch class. Use the Frequency field and the ElapsedTicks property to get the resolution you are looking for. Note though that the resolution of the stopwatch will change depending on the hardware. Read the link to the msdn documentation for more information.

Timer is starting late, hence shows the time which is a second late then actual time

I have a timer. But it starts a second late.I mean, i am clocking a time according to the timer. But the time in the clock, which updates through timer, is one second less then the actual time elapsed. The timer starts off a second late. How to set my timer to start at right time to show actual time? this is the code inside tick event:
if (currentState == play)
{
m_StatusLabel.Text = String.Format("Playing {0} ", format(timeCounter));
timeCounter++;
}
Here timeCounter is updating with each second.
Standard System.Windows.Forms timers give no guarantees about 'metronome quality'. For that, you would need either a Systems.Threading.Timer or a System.Timer.
Ref: Comparing the Timer Classes in the .NET Framework Class Library
There are no timers available that will gaurantee true-time accuracy, not even System.Threading.Timer can do that. For example, when you ask Threading.Timer to fire in 30ms, it might actually take 40ms or 200ms. Or if you ask for 1 second, it might fire in 1.01 seconds. In won't take long before your time is inaccurate.
The reason for this is that the timer makes the callback thread schedulable, but it still takes time for the thread scheduler to actually call the thread. Various operations the system is performing can delay that callback.
A Windows timer makes only one guarantee: it won't fire before the timeout interval elapses. Specifically, a thread will never receive a timer event while there are messages in its message queue.
Consequently you can't use timers to implement a clock. If you want to update a status message to show how long something has been playing, then you could try this: record the start time, and when your timer ticks get the current time, subtract the start time, and dislay the difference. Your status message won't be updated exactly every second, but when it is updated it will be correct.
Show a number 1 greater:
if (currentState == play)
m_StatusLabel.Text = String.Format("Playing {0} ",
format(++timeCounter) );
NOTE
Please consider the reason of those who suggested displaying the elapsed time as current time - start time. That is the way this is usually done. It is more accurate; a timer can be irregular on a busy system. It is still possible to update the displayed value every second. Pseudo code here for now(). This requires acquiring current time and performing a time difference.
if (currentState == play)
m_StatusLabel.Text = String.Format("Playing {0} ",
format( (now() - start)/1000 );
See Also:
1. DateTime.Subtraction
2. DateTime.Now

Categories