C# Substracting DateTimes is giving unrealistic result - c#

Here is my scenario:
Player places their finger or mouse on the “Home Position” marker at the bottom of the screen.
A timer begins counting to 500ms, if the user does not lift their finger or marker in that time the holdTimerElapsed is fired.
Inside this method, we display the next marker, delay for anywhere between 500ms to 1 second (so the user has a chance to see the next target). After the delay, an audio “GO” is played and a timer is started.
Inside the timer start method:
private void StartTimer()
{
startTime = DateTime.Now;
timer.Interval = ConfigurationService.GameConfig.MarkerTimeLimit;
timer.AutoReset = false;
timer.Start();
}
We log the "start time" of those movement. If the user is able to click the next target that popped up within the alotted time (4.5 seconds) we call the stop timer method:
private void StopTimer()
{
stopTime = DateTime.Now;
timer.Stop();
}
My problem:
"Randomly" the result of:
TimeSpan time = stopTime - startTime;
Minus the 500ms hold time will be an unrealistic 2-5 milliseconds - an impossible movement time for anyone but a bot.
I am at a complete loss for why the date times would be so close together giving such a small result.
More Code:
private void HandleMarkerClick(ScatterCircle selectedCircle)
{
StopTimer();
selectedCircle.Aquired = true;
aquiredTrainingCircles.Add(selectedCircle);
TimeSpan time = stopTime - startTime;
// movementTime here 'randomly' ends up as <10ms
long movementTime = (long) time.TotalMilliseconds - ConfigurationService.GameConfig.MarkerHoldTime;
}
I am only dealing with milliseconds in this case for bench-marking movements, and they need to be relatively accurate, anything less than 100ms is generally "to fast to be real"

To put an end to this question, I took Jon Skeet's advice and switched to the Stopwatch class. The client was still having inconsistent results.
I was unable to reproduce the issue, and long story short, the client was running the application on a laptop in power saving mode which I believe was causing the inconsistencies.
Switching from power saver mode to high performance seemed to fix the issue for the most part.

Related

Show System Time in WPF: Dispatcher timer

I am displaying time in my application using(basically in a label Datetime.Now formatted as hh:mm:ss tt) using a DispatcherTimer.
_timer = new DispatcherTimer {Interval = new TimeSpan(0, 0, 1)};
_timer.Tick += _timer_Tick;
_timer.Start();
private void _timer_Tick(object sender, EventArgs e)
{
try
{
var now = DateTime.UtcNow;
var nowUserSelected =
TimeZoneInfo.ConvertTimeFromUtc(now,
(DataContext as MainViewModel)?.UserSelectedTimeZone ?? TimeZoneInfo.Local);
ClockCurrent.Text = $"{nowUserSelected:hh:mm:ss tt}";
}
catch (Exception exp)
{
Log.Error("Error occurred while reporting time", exp);
}
}
The issue is that if the user opens a the Clock from the task bar(if you click on the time in the task bar there is pop up which displays the current time including seconds) sometimes the time in my app appears to be off by one second(sometimes!). Which I believe could be happening because the timer must be set to tick every second from the current time which could be 10:50:53 PM and 950 ms and it might be lets say and then it ticks every 54 and 950 ms ..... ms and so on , and since I am only displaying time till seconds it gives the illusion i am behind a whole second.
What is the recommended way to show the time which matches the time shown by the task bar, maybe set timer interval to tick every 500 ms ?
Check the ms when you are starting. Do first refresh right after full second, next refreshes each second
Even better: at the end of UI update you determine when the next UI update must happen.
#iPirat is correct, but I guess others did not understand what he meant, so let me first explain what is the problem and then how to solve it.
The DispatcherTimer runs on the WPF GUI thread. The advantage of this is that the code of DispatcherTimer.Tick can access any WPF control. The disadvantage is that once the 1 second since the last tick has expired, the WPF GUI thread might be busy with something else and the tick fires few milliseconds later. The next time Tick gets execute, there will be another small delay and this accumulates until the summed up delay becomes bigger than 1 second and you "loose" one tick.
You can prevent that by changing DispatcherTimer.Interval during each tick. If you want a tick every 1000 milliseconds and the tick was executed x milliseconds too late, you set DispatcherTimer.Interval to 1000-x milliseconds.
const int constantInterval = 1000;//milliseconds
private void Timer_Tick(object? sender, EventArgs e) {
var now = DateTime.Now;
var nowMilliseconds = (int)now.TimeOfDay.TotalMilliseconds;
var timerInterval = constantInterval -
nowMilliseconds%constantInterval + 5;//5: sometimes the tick comes few millisecs early
timer.Interval = TimeSpan.FromMilliseconds(timerInterval);
}
By the way, you might want to increase the priority like this DispatcherTimer timer = new DispatcherTimer (DispatcherPriority.Input);. This will make the delays a bit smaller, but the GUI gets still rendered fast enugh.
For more details see my article on CodeProject: Improving the WPF DispatcherTimer Precision

How do timers in a windows service behave when the system is asleep?

Assuming I have a windows service which has a timer that is set to run every 6 hours, I would expect it to fire 4 times a day. Let's say : 0000, 0600, 1200 1800. (Military time, same as 00:00, etc...)
If the system goes to sleep at 1000, and wakes at 1700, what happens?
will it fire again at 1900, because it has 2 hours on the timer?
will it fire straight away (because it missed it's 1200 appointment), and then fire again at 2300 (adding it's 6 hours to the current time?)
I've noticed that when the computer goes to sleep, it doesn't fire the OnPause or OnContinue methods.
If anyone can shed some light on the behaviour of the system in the above cases, It'll be great know.
Cheers, and thanks in advance.
As has already been mentioned in the comments: Use the task scheduler instead of timers. See this article for further discussion.
The question of how timers behave during sleep is still interesting, though. In the specific case you mention, option 2. will be the observed behavior. The timer will fire on resume because it missed an event during sleep and subsequently start counting from 0 again The next time it fires will thus be at 23:00. This answer has sample code to support the observation.
In case you want to detect when the system sleeps and resumes, subscribe to the SystemEvents.PowerModeChanged event. This event's PowerModeChangedEventArgs contains a Mode, of which you are interested in Suspend and Resume.
For my needs, I ended up going with a windows service that will check if and when next operation needs to be carried, and simply set the timer to that time.
The windows service will update that time upon resuming from sleep.
The benefits are :
Unaffected by sleep/wake times
no console apps being run by a scheduler.
using NLog (quick tutorial here) and Growl (how to use Growl with NLog tutorial here) to receive notifications on the desktop
having a log on the system as well
Since my case is simple, having the functionality is already in a separate dll, I don't have any issues with stability or memory leaks (and if I do, shame on me). This keeps what I need happening once a day, or once every time the computer wakes up, and doesn't incur extra overhead on the system.
Like Henrik replied and linked, the correct answer is number 2.
I've wrote the following in linqpad, which is similar to the link in the above answer:
static int counter = 0;
static System.Timers.Timer my_timer;
void Main()
{
// Set up a timer to trigger every minute.
my_timer = new System.Timers.Timer();
DateTime now = DateTime.Now;
my_timer.Interval = (60 - now.Second) * 1000; // Fire at beginning of minute
string.Format("First tick in {0} seconds", my_timer.Interval/1000).Dump();
my_timer.Elapsed += OnTimer;
my_timer.Start();
while (counter < 5) { // sleep away until 5 ticks happen
Thread.Sleep(5000);
}
// stop timer and say goodbye
my_timer.Stop();
DateTime.Now.Dump("Finished running, shutting down");
}
// Print time and counter every timer tick
void OnTimer(object sender, System.Timers.ElapsedEventArgs args)
{
if (my_timer.Interval != 60000) // set to one minute after first time
my_timer.Interval = 60000;
DateTime.Now.ToString("HH:mm:ss.fff").Dump("On Timer fired:");
(counter++).Dump("Static counter :");
}
Getting the results:
First tick in: 37 seconds
On Timer fired : 08:47:00.552
Static counter : 0
On Timer fired : 08:48:00.557
Static counter : 1
On Timer fired : 08:49:00.571
Static counter : 2
// Shut computer down for 3 minutes at 08:49:30
On Timer fired : 08:52:33.509
Static counter : 3
On Timer fired : 08:53:33.510
Static counter : 4
Finished running, shutting down
1/09/2014 8:53:38 AM
So, obviously the computer knows it missed a tick, it fires the method once, and continues from there. Note that it only fires once.
But would be happy if someone who knows what happens behind the scenes can shed some more light on this.

C# Timer -- measuring time slower

I'm writing a code where:
I.)
The user adds "events" during run-time. (To a flowlayoutpanel) These events are turning some LEDs on/off, after "x" time has elapsed and the LED-turning functions are written in a Led-function.cs class.
i.e:
1) Turn left led on After 3500ms
2) Turn right led on After 4000ms
II.)
When the user hits start a timer starts.
// Create timer.
System.Timers.Timer _timer;
_timer = new System.Timers.Timer();
_timer.Interval = (1);
_timer.Elapsed += (sender, e) => { HandleTimerElapsed(LedObject, device, _timer); };
_timer.Start();
III.)
The timer's tick event is raised every millisecond and checks if the user definied time has ellapsed. Im measuring the elapsed time with adding +1 to an integer at every tick event. (NumberOfTicks++;)
//Timer Handle
private void HandleTimerElapsed(Led_Functions LedObject, string device, System.Timers.Timer _timer)
{
NumberOfTicks++;
if (NumberOfTicks >= Start_time[0])
{
LedObject.LeftLED_ONnobutton(device);
}
}
IV.) What I noticed was that when the tick was set to 1. (So the tick event is raised every millisecond) Even if I set 3000ms to the evet the LED actually flashed around 6 seconds.
When the tick was set to 100. (So every 0,1s) then the flash was more accurate (3,5sec or so).
Any Ideas why im having this delay in time?
Or do you have any ideas how could I implement it better?
Thank you!
1ms is a really small interval for CPUs. You cannot ensure your code get called every 1ms especially when the system has some heavy work to do.
A better implement is to use DateTime.Now - startTime to get the time span or use Stopwatch.
private Stopwatch stopwatch = new Stopwatch();
// start the stopwatch:
stopwatch.Start();
// Timer Handle:
numberOfTicks = stopwatch.ElapsedMilliseconds;

How to execute code at a specific exact time (far from now) in C#?

I am developping a Windows Service that has to execute a method at a specific exact time.
When the service starts, it extracts several different DateTimes from an SQL Server database and should then start a thread for each DateTime. Each thread should wait until the exact DateTime value, then do some work, then wait again for a shorter period of time and then do some final work again.
I don't want to use System.Timers.Timer because:
the method has to be executed at the exact specified time
this exact time could be in more than 24h
I need to pass a parameter to the Elapsed event
How can I implement this?
Thank you.
EDIT: I just had an idea last night, what if I write a dynamic polling timer? For exemple, if the due datetime is in more than 12 hours it can poll the time every hour to re-synchronize. Then if the due datetime is in more than 3 hours it can poll the time every 30min and so on... What do you think? Would that be a bad code to write?
Thank you again.
You can't pass a parameter to the tick event with System.Timers.Timer, but you can with System.Threading.Timer. The delay time "greater than 24 hours" is no problem. The timers use a 32 bit period that is expressed in milliseconds. 2^31 milliseconds works out to something like 24.85 days. There's also an overload that lets you specify the delay with a 64-bit signed integer. 2^63 milliseconds is ... several hundred million years.
But having those timers tick at an exact date/time far in the future is problematic because you have to specify the delay time, and a clock change will cause your delay to be too short or too long (think Daylight Saving Time, or user-initiated time changes). You can specify the tick time and have a timer poll the current time every second. It's kind of ugly, but it works.
Another option is to use the Windows Waitable Timer object, which lets you set an exact date and time. Unfortunately, the Framework doesn't include a corresponding object. I wrote an article about it some years ago and published the code. The article is no longer available online, but you can download the code from http://mischel.com/pubs/waitabletimer.zip.
I have used something called ManualResetEvent in the past with a lot of success. Assuming that you know the exact time to run your code then you will be able to calculate estimated time to run (TTR) and subsequent runs should be configured within the first run.
partial class SomeService : ServiceBase
{
private ManualResetEvent stop = new ManualResetEvent(false);
private List<DateTime> times;
private int idxDT = 0;
public SomeService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
this.stop.Reset();
//implement you logic to calculate miliseconds to desired first run time
int miliseconds_to_run = 1;
ThreadPool.RegisterWaitForSingleObject(this.stop,
new WaitOrTimerCallback(ThreadFunc),
null,
miliseconds_to_run,
true);
}
private void ThreadFunc(object _state, bool _timedOut)
{
if (_timedOut)
{
if(this.times == null)
{
//get a list of times to run, store it along with the index of current TTR
this.times = new List<DateTime>();
}
int miliseconds_to_run = (this.times[this.idxDT++] - DateTime.Now).Miliseconds;
ThreadPool.RegisterWaitForSingleObject(this.stop,
new WaitOrTimerCallback(ThreadFunc),
null,
miliseconds_to_run,
true);
}
}
protected override void OnStop()
{
this.stop.Set();
}
}
Of course this highly depends how exact your job start time has to be. ThreadPool class will send a Thread alocation request to the OS, and then it will wait for the next available Thread from the Pool. In some processes with lots of lots of threads this could lead to Thread starvation and your exact times will be late.
You could also try creating Task Scheduler Jobs from .NET but I've never done that before.
Even though you said you don't want to use System.Timers.Timer I'll show you how to do it anyway, as bullet 1 and two in your question don't seem to be valid points against using it in my opinion.
So here's what I do in several applications of mine:
// 1. Create the timer
System.Timers.Timer timer = new System.Timers.Timer();
timer.AutoReset = false;
timer.Elapsed += ...;
// 2. Calculate the number of milliseconds between the scheduled time and the current time
timer.Interval = (scheduledDate - DateTime.Now).TotalMilliSeconds;
// 3. Start the timer
timer.Start();
Done. The event will fire "roughly" at the desired time. Please note that this doesn't work down to the exact millisecond, as Windows is not a real-time OS.
I did face sort-off similar issue and used below solution which might solve your issue.
I used ManualResetEvent class, added a Wait method and made the service wait for the exact time.
protected ManualResetEvent waitEvent = new ManualResetEvent(false);
protected bool Wait(int milliSecs)
{
return !this.waitEvent.WaitOne(milliSecs, true);
}
I used this Wait in OnStart method as below:
protected override void OnStart(string[] args)
{
DateTime nextRun = dt;//datetime from the database
YourProcessOrThreadToRun process = new YourProcessOrThreadToRun();
while (Wait((int)nextRun.Subtract(DateTime.Now).TotalMilliseconds))
{
process.StartProcess();
}
}
YourProcessOrThreadToRun is the thread you want to run on that exact time.

C#, System.Timers.Timer, run every min in sync with system clock

I am trying to get a timer run every minute in sync with the system clock (00:01:00, 00:02:00, 00:03:00, etc). Will the following code produce a stable timer? I've tried running it. The timer does precisely run every min. But the question is will it start to wander off, say, after several months?
private System.Timers.Timer timer;
public frmMain()
{
timer = new System.Timers.Timer();
timer.AutoReset = false;
timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
timer.Interval = GetInterval();
timer.Start();
}
private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
//Do processing
timer.Interval = GetInterval();
timer.Start();
}
private double GetInterval()
{
DateTime now = DateTime.Now;
return ((60 - now.Second) * 1000 - now.Millisecond);
}
It won't.
DateTime.Now uses the system clock as the reference timer, so your timer will always stay in sync with it, modulus the few milliseconds of system clock resolution.
I don't see how it can wander off, everytime the timer ticks, it determines how long it is to the next exact minute and sets the interval accordingly. In theory it is actually quite ingenious, because I timer by itself would wander off. The only way to know for sure would be to test it of course, so as long as your UI doesn't freeze for more then 60 seconds, (maybe 50s to play it safe) there won't be a problem. Keep in mind that laptops will often go to sleep when left for a time, or the lid is closed, this will cause a glitch.
Depending on what you are attemping to do though, why not just use the system time, to send an event everytime the minute changes?
The big picture looks fine, GetInterval will always return a positive value, and so on. I only see a few caveats:
If standby/resume happens then you may have one run at a non-round time
If timer_Elapsed takes more than a minute to complete then you will miss a beat
If the system is so overloaded that timer_Elapsed is scheduled 40/50 seconds in delay AND timer_Elapsed takes more than 60 - delay seconds, you will miss a beat
Your code won't drift, but there will (inevitably) be jitter as Timer callbacks are rarely bang on the requested interval.
The only potential problem I can see with this code is if the ThreadPool were under such strain that your timer callback was not dequeued and executed within a minute interval, resulting in a skipped minute.
This seems somewhat unlikely, but not completely beyond the realms of possibility.

Categories

Resources