inaccurate .NET timer? - c#

I'm developing an application and I need to get the current date from a server (it differs from the machine's date).
I receive the date from the server and with a simple Split I create a new DateTime:
globalVars.fec = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, int.Parse(infoHour[0]), int.Parse(infoHour[1]), int.Parse(infoHour[2]));
globalVars is a class and fec is a public static variable so that I can access it anywhere in the application (bad coding I know...).
Now I need to have a timer checking if that date is equal to some dates I have stored in a List and if it is equal I just call a function.
List<DateTime> fechas = new List<DateTime>();
Before having to obtain the date from a server I was using computer's date, so to check if the dates matched I was using this:
private void timerDatesMatch_Tick(object sender, EventArgs e)
{
DateTime tick = DateTime.Now;
foreach (DateTime dt in fechas)
{
if (dt == tick)
{
//blahblah
}
}
}
Now I have the date from the server so DateTime.Now can't be used here. Instead I have created a new timer with Interval=1000 and on tick I'm adding 1 second to globalVars.fec using:
globalVars.fec = globalVars.fec.AddSeconds(1);
But the clock isn't accurate and every 30 mins the clock loses about 30 seconds.
Is there another way of doing what I'm trying to do? I've thought about using threading.timer instead but I need to have access to other threads and non-static functions.

Store the difference between the server's time and local time. Calculate the servers' time when you need it using that difference.

If you create atimer with an interval of 1000ms, it will be called no sooner than 1000ms. So you can pretty much guarantee that it will be called in more than 1000ms, which means you will "lose" time by adding 1s on this timer tick - This will accumulate error with every tick. A better approach is to record a start time and use the current time to determine the current offset from that known start time, so that you don't accumulate any error in your time keeping. (There will still be some error, but you will not drift out of touch with real-time over time)
Different timers (Forms.Timer, Thread.Timer etc) will give different accuracies as well - Forms.Timer is particularly poor for accuracy.
You could also use a high performance time to keep track of the time better - see here, for example.

Here is a reliable 1 μs Timer
See https://stackoverflow.com/questions/15725711/obtaining-microsecond-precision-using-net-without-platform-invoke?noredirect=1#comment22341931_15725711
I guarantee its faster and more accurate then StopWatch and PerformanceCounters and uses the fractions of a second you have in the time slice wisely!

Related

C# - most efficient way of measuring ellapsed time

I am working on a C# console application in which I need to know the ellapsed time since the program has started.
I have a variable that stores the time on start (DateTime now = DateTime.Now;)
What is the most efficient way of measuring the ellapsed time?
The ellapsed time can be hours - this is why I am concerned about efficiency and memory usage.
Thanks in advance!
Subtract the current time from the time the program started. This will return a TimeSpan which exposes properties like TotalHours which you can use to calculate the elapsed time.
// on start
var startTime = DateTime.UtcNow;
// later on, to see hours elapsed since then
var elapsed = (DateTime.UtcNow - startTime).TotalHours;
Don't worry. Measuring a time span does not use any resources, as it just compares now with then.
DateTime start = DateTime.Now;
// do some heavy calculation
TimeSpan delta = DateTime.Now - start; // get the time that elapsed
This does not use any resources except the variable for the start, which is just a 64 bit counter.
Note that for short timespans you're better off using Stopwatch, as this is not subject to time adjustments that may happen between start and now.

Why is time not incrementing

I am trying to show the timestamp of when a process begins and when it completes, but my time never increments (even though time in reality does)
DateTime now = DateTime.Now;
txt1.AppendText(now + Environment.NewLine);
//Lengthy process that usually takes 2 - 3 minutes
txt1.AppendText(now);
You are literally using the same variable with the same value as when you first displayed it. You would need to get the time again like this...
DateTime now = DateTime.Now;
txt1.AppendText(now + Environment.NewLine);
//Lengthy process that usually takes 2 - 3 minutes
DateTime timeHasPassed = DateTime.Now;
txt1.AppendText(timeHasPassed);
DateTime is a ValueType. When you assign it to a variable, you are making a copy of the value, not the reference.
This means that when you use DateTime.Now, you have to invoke it via the Get Property to get the latest time value.
txt1.AppendText(DateTime.Now + Environment.NewLine);
//Lengthy process that usually takes 2 - 3 minutes
txt1.AppendText(DateTime.Now);
That's because you captured and stored the DateTime.Now in a variable so it shows the stored value. Use DateTime.Now again instead of using now variable.
Don't use DateTime to measure your process time of your code.
You should never do any increment or math with DateTime.Now because it may be ambiguous due to DST and TimeZone issues.
Use StopWatch to measure elapsed time instead. This class offers high-precision timing in .NET. It is capable of measuring time with sensitivity of around 100s of nanoseconds.
You can use it's Start and Stop methods to control of a StopWatch object.

Update UI element from thread

I try to create in windows phone timer which update every 10-15 ms (for UI element). And i want have opportunity to append time. So i create TimeSpan and DispatcherTimer where interval = 15 ms. So every 15 ms call the event where i subtract 15 ms to timeSpan and when timespan <= 0 i call some method. When i set TimeSpan 4 seconds (for example) in life passed more than 4 sec about 4,6 sec. Also i tryed to use async/await but this did't work. I tryed to use System.Threading but i don't know how to update element which was create in the other thread.
So every 15 ms call the event where i subtract 15 ms to timeSpan and when timespan <= 0 i call some method.
Your logic is flawed. You can't possibly update your timespan this way because:
As Stephen Cleary mentioned in his answer, you have no guarantee that the timer will fire at exactly 15 ms
Even if it did, it doesn't take into account the time needed to actually update your timespan (say that it takes 1ms to compute the new timespan, your timer will drift of 1ms every 15ms)
To have an accurate time, you need to store the timestamp at which you started it (retrieve it by using DateTime.UtcNow. Every time your timer tick, take the new timestamp and substract to the one you saved. This way, you know exactly how much time has passed and your timer will never drift.
private DateTime start; // Set this with DateTime.UtcNow when starting the timer
void timer_Tick(object sender, EventArgs e)
{
// Compute the new timespan
var timespan = DateTime.UtcNow - start;
// Do whatever with it (check if it's greater than 4 seconds, display it, ...)
}
So every 15 ms call the event where i subtract 15 ms to timeSpan
And there's your problem.
When you set a timer on any Windows platform, you can't expect a huge level of precision. On the desktop I believe the normal scheduler period on consumer hardware is ~12ms (and of course other apps can throw that off considerably). I have no idea what the scheduling is like on the phone but I assume it's less accurate than desktop (for battery lifetime reasons).
So, you simply can't approach this problem that way on Windows, because you can't assume that a timer will fire every 15ms. Instead, just start the DispatcherTimer to the full time span that you need, e.g., 4 seconds.
Try this to update UI element in your timer thread
Dispatcher.BeginInvoke(() =>
{
//Update Your Element.
});

datetime checking for specific time

I have a windows service and I would like to insert a timer. How can I check if the present time is 9:00 AM ?
I would like my service to check this every day. Thank you a lot
My try:
Datetime dt=Datetime.parse("09:00:00 everyday");
if(datetime.now -dt ==0)
{
//fire event
}
Thats kinda sily of me though.
You need to make a timer and sets its interval to the timespan between now and tomorrow 9:00 AM. Next time the timer tick, set the interval again in the same way.
You should use this Timer class:
http://msdn.microsoft.com/en-us/library/system.timers.timer.aspx
Please use DateTime.UtcNow.Hour to check current hour
By using UtcNow you will gets a DateTime object that is set to the current date and time on the computer, expressed as the Coordinated Universal Time (UTC).
var now = DateTime.Now;
var today = now.Date;
var nineAm = today.AddHours(9);
TimeSpan ts = nineAm - now;
var timeInMillisecondsTill9Am = ts.Milliseconds;
If(timeInMillisecondsTill9Am==0)
{
//your code goes here
}
Since you don't know when someone may shutdown or reboot your computer or service then you need to make sure that you use a method robust enough to handle these kinds of interruptions.
I suggest that when your service checks every 5 minutes or so if the time is after 9am and if the last run date is yesterday. If so, you update the last run date to day (perhaps in a simple text file) and then run the "9:00am" task. In this way your task only runs once per day, fairly close to 9am, and is robust against reboots.
You'll need to use a standard .NET timer to trigger the checks - and if you're clever enough you can make it fire a few seconds after 9am.
Let me know if that's a good solution.

How to send reminders at correct time for users in different timezones?

I have never created a reminder application. Here is how I see it. Please let me know if I'm on the right way.
So I have users from different timezones.
ID DateTimeUTC TimeZoneID
1 2011-07-12 02:15:15.000 TimeZneID1
2 2011-07-13 16:00:00.000 TimeZneID2
3 2013-11-03 17:00:00.000 TimeZneID3
4 2011-08-22 03:00:00.000 TimeZneID4
5 2011-07-16 22:00:00.000 TimeZneID5
Create a scheduled process to run every 15 mins and do the steps below:
Get records;
The second is to convert DateTimeUTC to Time for the right timezone
Compare if it's match
a. Send Reminder
var tzi = TimeZoneInfo.FindSystemTimeZoneById(TimeZneID1);
var local = TimeZoneInfo.ConvertTimeFromUtc(DateTimeUTC, tzi);
var timeNow = TimeZoneInfo.ConvertTimeFromUtc(DateTime.Now, tzi);
if(local == timeNow)
SendReminder();
Is it efficient way? is it the right way?
If date/time values are already in UTC in the database, you don't need to perform any conversions, surely... you just need to see whether the current UTC instant is a match, and if so, send the reminder.
That's assuming you really mean it's UTC in the database, i.e. you've converted it from the user's local time when they entered the reminder (assuming they did so to start with).
Typically, when dealing with dates like this, you would do all of your calculations in UTC and only switch to local time when it's time (no pun intended) to display the results. I assume from your question that this is a centralized database that's managing all the tasks, and you just need them to run at the correct local time?
if ( dateTimeUtc == DateTime.UtcNow )
{
// If your reminder needs to display the local time, pass it in:
var tzi = TimeZoneInfo.FindSystemTimeZoneById(TimeZneID1);
SendReminder(TimeZoneInfo.ConvertFromUtc(DateTime.UtcNow, tzi));
}
Note that DateTime.Now is in local time; you want DateTime.UtcNow for consistancy across time zones.
Another thing to be aware of is you are only running your task scheduler every 15 minutes, so the odds of times like 02:15:15 matching exactly are slim. What you would typically want to do is check for any reminder times that came up since the last run:
var currentRun = DateTime.UtcNow;
foreach ( dateTimeUtc in GetReminderDateTimes() )
{
if ( dateTimeUtc > lastRun && dateTimeUtc <= currentRun )
{
}
}
lastRun = currentRun;
In my opinion you might be over-complicating it. Since you are storing things in UTC, have the reminders in UTC, and match on UTC. Then just associate the reminders with the users that you want to remind.
I want to do similar stuff and have been debating what would be an appropriate approach. Essentially, I am writing an application which would send a message for a particular country at midnight (localtime). I have about 100 such countries and I have to also be mindful of daylight savings. I can only think of 2 ways to do this,
1. Create a corresponding thread for each country and which wakes up every hour or so and checks if it is midnight(local time) and send out the message. So essentially, I will be creating 100 threads doing nothing most of the time.
2. In this approach, there will be only one timer which checks every minute or 30 secs the local time for 100 countries and send message. There will need to be some extra logic as there will never be an exact midnight match.
Not sure, if there is any better way to tackle above situation. It would be great if I can get some ideas/suggestions here.
Thanks,
SP.

Categories

Resources