Calculating a timeout that is suspended during certain periods - c#

I've been tasked with writing a method that calculates, given a start datetime and timeout in minutes, the datetime that the timeout should occur.
However the timeout should only 'tick' during certain times on certain days, which is determined by a non tick start datetime, non tick stop datetime and a list of open days.
For example, given the following:
Start datetime: Friday 21/02/2014 15:00
Timeout: 720 minutes (12 hours)
Open days: Monday,Tuesday,Wednesday,Thursday,Friday
Non tick start time: 09:00
Non tick stop time: 18:30
The calculated timeout datetime should be Monday 24/02/2014 17:30 (as it does not tick on Saturday and Sunday).
I'm writing this in C#, but its technically language agnostic.
Is there an 'elegant' way of doing this? Or is it simply a case of looping and adding additional time where its determined that timeout should stop ticking?

If you set up a timer to tick every period (e.g. every second), you can increment a number of ticks in the timer's callback handler.
I would approach in one of the following ways. Either I could run the callback every second no matter what, and in the callback I could check whether I'm suppose to increment or skip the increment for this period (inside the non-tick time period).
Otherwise, I could increment every time no matter what, and then have a check to see if the non-tick period is approaching and, if so, then adjust the timer's callback time to run the next callback after the non-tick time period has elapsed.

Related

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.
});

settting in code a timer to run prgram.

I have an application which I am running using windows scheduler every 30 minutes, I also have a config file which is a datatable called config. I am going through each of the rows, which has a schedule column and if the time is in the 30 minute window the program should run the whole program. The time windows are 12:00:00 and 12:30:00 and so on, as can be seen I'm checking the current time and the row time as can be seen blow, how would I make it run?
I tried the if statement below to see if it runs are the current time only and it doesn't work any ideas why this would be
TimeSpan time = DateTime.Now.TimeOfDay;
TimeSpan runningTime = DateTime.Parse(dr["scheduledTime"].ToString()).TimeOfDay;
if (time == runningTime)
If the time isn't exactly on the hour or half past the hour, the code in your if statement won't run, try this instead:
TimeSpan time = DateTime.Now.TimeOfDay;
TimeSpan runningTime = DateTime.Parse(dr["scheduledTime"].ToString()).TimeOfDay;
if (time >= runningTime && time <= (runningTime + new TimeSpan(0, 30, 0)))
When your program runs, DateTime.Now.TimeOfDay will contain something similar to 13:27:37, which obviously won't be equal to 13:00:00. So all you do is check that the current time is within the 30 minute window. We achieve that by checking that the current time elapsed since midnight (which is what .TimeOfDay on a DateTime gives you) is greater than or equal to the time elapsed since midnight of the TimeSpan you retrieve from your DataTable, and that it is also less than or equal to that same time slot plus 30 minutes.

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.

Trigger event using timer on a specific day and time

I am using System.Timer to trigger an event. Currently I trigger it every 1 hour and check if it matches the configured value (day,time).
But it is possible to trigger this at a specific time? like suppose on Sunday at 12Am.
Windows Task Scheduler would be more appropriate but its not an option.
Thanks in advance
It isn't clear why you just wouldn't set the timer's Interval to the target date/time. There's a limit on the number of milliseconds, you can time up to 2^31 milliseconds, 27 days. You'll be good as long as you can stay in that range.
private static void SetTimer(Timer timer, DateTime due) {
var ts = due - DateTime.Now;
timer.Interval = ts.TotalMilliseconds;
timer.AutoReset = false;
timer.Start();
}
The timer doesn't support this kind of interval but you could check every 20 seconds for the current day and time.
Edit Sorry you are doing that already... why not make the interval half the time left each time you check (A Zeno timer)?
In a similar situation, I'm using System.Threading.Timer to achieve this. Basically I set its due time to desiredDateTime - DateTime.Now, so that it will tick at desiredDateTime.
If you get another date meanwhile, you can user Timer.Change() to change the tick time to the new date. Don't forget to Dispose() the Timer when you no longer need it!

inaccurate .NET timer?

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!

Categories

Resources