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.
Related
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.
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.
I'm trying to get a Timer to trigger twice a day, instead of a steady timespan.
I want to trigger the callback at say 07:00 and again at 16:00, then repeat the next day at 07:00.
For some reason it's eluding me, this doesn't seem that hard, but I'm thinking I have to build a new Timer each day and kill it and end of day?
Why not just have a timer that ticks every hour and then only respond to the events at 7:00 and 16:00?
var timer = new Timer(TimeSpan.FromHours(1).TotalMilliseconds);
timer.Elapsed += TimerHandler;
void TimerHandler(object sender, EventArgs e) {
var hour = DateTime.Now.Hour;
if (hour != 7 && hour != 16) {
return;
}
...
}
Do you really need to use a long running timer to achieve this? If you're waiting to perform a specific task, it's probably a better idea to write a console application that does whatever you need. You can then set up a scheduled task to run your application whenever you need; see http://windows.microsoft.com/en-US/windows7/schedule-a-task.
Maybe it is a good idea to trigger it every hour and check in the callback if the needed functionality has to be performed. When later you decide to change the times or even change the amount of triggers per day it can be done one one location without recreating the timer.
E.g. pass a list to the timer (extended) class that keeps the times when to really doing something and check this list every hour.
Based on the information in this thread I decided to author a "scheduler" library for NETMF. It is similar in implementation to the timer pattern, but is based on TimeDate to specify the event.
You can get the library at https://github.com/pelogical/mfschedule
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
I'm working on a program that will need to delete a folder (and then re-instantiate it) at a certain hour of the day, and this hour will be given by the user.
The hour will most likely be during the night, because that's when nobody is accessing the folder (it's outside working hours). Is there a way to trigger that event at that certain hour?
I know about timers, but is there an easier way to do this without a timer that ticks and checks to see what time it is?
EDIT: Maybe I wasn't specific enough. I want to trigger a method to do something, without having to first compile it in a separate executable. This method is part of a bigger class that is implemented as a Windows Service. So this service continuously runs, but at a certain time of day, it should trigger this function to delete the folder.
Thanks.
Think out of the box.
No need for coding on this kind of job - use Scheduled Tasks, they have been in windows for a long time. You can kick off your program from this.
Update: (following update to question)
If you need to trigger a method from an already running service, use a timer and test DateTime.Now against your target time.
If you want to do this in your code you need to use the Timer class and trigger the Elapsed event.
A. Calculate the time left until your first runtime.
TimeSpan day = new TimeSpan(24, 00, 00); // 24 hours in a day.
TimeSpan now = TimeSpan.Parse(DateTime.Now.ToString("HH:mm")); // The current time in 24 hour format
TimeSpan activationTime = new TimeSpan(4,0,0); // 4 AM
TimeSpan timeLeftUntilFirstRun = ((day - now) + activationTime);
if(timeLeftUntilFirstRun.TotalHours > 24)
timeLeftUntilFirstRun -= new TimeSpan(24,0,0); // Deducts a day from the schedule so it will run today.
B. Setup the timer event.
Timer execute = new Timer();
execute.Interval = timeLeftUntilFirstRun.TotalMilliseconds;
execute.Elapsed += ElapsedEventHandler(doStuff); // Event to do your tasks.
execute.Start();
C. Setup the method do execute what you want to do.
public void doStuff(object sender, ElapsedEventArgs e)
{
// Do your stuff and recalculate the timer interval and reset the Timer.
}
When
the program starts
the timer was changed
the event has finished
calculate the remaining time (in milliseconds) and set the Timer interval.
Use Windows Scheduler. There you can specificy which file is executed when.
A possible start or guideline : NCrontab
The programmatic interface for Scheduled Task is COM-based, so it should be relatively easy to use it from .NET (though I've never tried myself).