Timer resets after 60 seconds - c#

Below is the code that I'm attempting to use as an elapsed timer on a desktop task timer that we're building. Right now when this runs it only counts to 60 seconds and then resets and doesn't ever add to the minutes.
//tick timer that checks to see how long the agent has been sitting in the misc timer status, reminds them after 5 mintues to ensure correct status is used
private void statusTime_Tick(object sender, EventArgs e)
{
counter++;
//The timespan will handle the push from the elapsed time in seconds to the label so we can update the user
//This shouldn't require a background worker since it's a fairly small app and nothing is resource heavy
var timespan = TimeSpan.FromSeconds(actualTimer.Elapsed.Seconds);
//convert the time in seconds to the format requested by the user
displaycounter.Text=("Elapsed Time in " + statusName+" "+ timespan.ToString(#"mm\:ss"));
//pull the thread into updating the UI
Application.DoEvents();
}

Quick Fix
I believe the problem is that you are using Seconds which is 0-59. You want to use TotalSeconds with your existing code:
var timespan = TimeSpan.FromSeconds(actualTimer.Elapsed.TotalSeconds);
Comments
However, this doesn't make a lot of sense as you could just use the TimeSpan object directly:
var timespan = actualTimer.Elapsed;
Also, I can't see all your application, but I would expect you do not need to call Application.DoEvents();. As the UI should update automatically when it has the chance... if it doesn't then you want to look at moving whatever code is blocking the UI to a different thread.
Recommendation
With all that said, I would recommend you don't use a timer to track elapsed time at all. Timers can lose accuracy over time. The best approach is to store the current system time when you start the process, then when you need to display the 'timer' do an on-demand calculation at that point.
A very simple example to help explain what I mean:
DateTime start;
void StartTimer()
{
start = DateTime.Now;
}
void UpdateDisplay()
{
var timespan = DateTime.Now.Subtract(start);
displaycounter.Text = "Elapsed Time in " + statusName + " " + timespan.ToString(#"mm\:ss"));
}
You could then use a timer to call your UpdateDisplay method at regular intervals:
void statusTime_Tick(object sender, EventArgs e)
{
UpdateDisplay();
}

Related

Execute a function ever 60 seconds

I want to execute a function every 60 seconds in C#. I could use the Timer class like so:
timer1 = new Timer();
timer1.Tick += new EventHandler(timer1_Tick);
timer1.Interval = 60 * 1000; // in miliseconds
timer1.Start();
Question is I have a long running process. Occasionally it make take several minutes. Is there a way to make the timer smart so if the function is already being executed then it should skip that cycle and come back 60 seconds later and if again it is in execution then again skip and come back 60 seconds later.
I would suggest you to have a class member variable bool variable with value false.
then in click event return if its true at the beginning.
and then set it to true, so that it will tell you that its currently in execution.
then write your logic.
and then once done finally set it to false again.
code will look like this.
private bool isRunning = false;
private void timer1_Tick(object sender, EventArgs e)
{
if (isRunning)
{
return;
}
isRunning = true;
try
{
... //Do whatever you want
}
finally
{
isRunning = false;
}
}
The modern and most clean way to do this is using Microsoft's new Period Timer:
var timer = new PeriodicTimer(TimeSpan.FromSeconds(n));
while (await timer.WaitForNextTickAsync())
{
//Business logic
}
If you need to abort such a ticker, you can pass a cancellation token to the WaitForNextTickAsync method.
Another advantage is this:
The PeriodicTimer behaves like an auto-reset event, in that multiple ticks are coalesced into a single tick if they occur between calls to WaitForNextTickAsync(CancellationToken). Similarly, a call to Dispose() will void any tick not yet consumed. WaitForNextTickAsync(CancellationToken) may only be used by one consumer at a time, and may be used concurrently with a single call to Dispose().
Source: https://learn.microsoft.com/en-us/dotnet/api/system.threading.periodictimer.waitfornexttickasync?source=recommendations&view=net-7.0#remarks
If you need more granularity (like "always at 10 am", use something like https://github.com/HangfireIO/Cronos
Use a timer, set it to 60 second
On Event:
try
Stop timer
Do logic
catch
What ever fail recovery
finally
Start the timer
Logic is run 60 seconds after last finish.
You can use a Stopwatch inside a loop: start the stopwatch, after 60 second call the function, reset the stopwatch, start the loop again.

Run code at a certain time [duplicate]

I have a service written in C# (.NET 1.1) and want it to perform some cleanup actions at midnight every night. I have to keep all code contained within the service, so what's the easiest way to accomplish this? Use of Thread.Sleep() and checking for the time rolling over?
I wouldn't use Thread.Sleep(). Either use a scheduled task (as others have mentioned), or set up a timer inside your service, which fires periodically (every 10 minutes for example) and check if the date changed since the last run:
private Timer _timer;
private DateTime _lastRun = DateTime.Now.AddDays(-1);
protected override void OnStart(string[] args)
{
_timer = new Timer(10 * 60 * 1000); // every 10 minutes
_timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
_timer.Start();
//...
}
private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
// ignore the time, just compare the date
if (_lastRun.Date < DateTime.Now.Date)
{
// stop the timer while we are running the cleanup task
_timer.Stop();
//
// do cleanup stuff
//
_lastRun = DateTime.Now;
_timer.Start();
}
}
Check out Quartz.NET. You can use it within a Windows service. It allows you to run a job based on a configured schedule, and it even supports a simple "cron job" syntax. I've had a lot of success with it.
Here's a quick example of its usage:
// Instantiate the Quartz.NET scheduler
var schedulerFactory = new StdSchedulerFactory();
var scheduler = schedulerFactory.GetScheduler();
// Instantiate the JobDetail object passing in the type of your
// custom job class. Your class merely needs to implement a simple
// interface with a single method called "Execute".
var job = new JobDetail("job1", "group1", typeof(MyJobClass));
// Instantiate a trigger using the basic cron syntax.
// This tells it to run at 1AM every Monday - Friday.
var trigger = new CronTrigger(
"trigger1", "group1", "job1", "group1", "0 0 1 ? * MON-FRI");
// Add the job to the scheduler
scheduler.AddJob(job, true);
scheduler.ScheduleJob(trigger);
A daily task? Sounds like it should just be a scheduled task (control panel) - no need for a service here.
Does it have to be an actual service? Can you just use the built in scheduled tasks in the windows control panel.
The way I accomplish this is with a timer.
Run a server timer, have it check the Hour/Minute every 60 seconds.
If it's the right Hour/Minute, then run your process.
I actually have this abstracted out into a base class I call OnceADayRunner.
Let me clean up the code a bit and I'll post it here.
private void OnceADayRunnerTimer_Elapsed(object sender, ElapsedEventArgs e)
{
using (NDC.Push(GetType().Name))
{
try
{
log.DebugFormat("Checking if it's time to process at: {0}", e.SignalTime);
log.DebugFormat("IsTestMode: {0}", IsTestMode);
if ((e.SignalTime.Minute == MinuteToCheck && e.SignalTime.Hour == HourToCheck) || IsTestMode)
{
log.InfoFormat("Processing at: Hour = {0} - Minute = {1}", e.SignalTime.Hour, e.SignalTime.Minute);
OnceADayTimer.Enabled = false;
OnceADayMethod();
OnceADayTimer.Enabled = true;
IsTestMode = false;
}
else
{
log.DebugFormat("Not correct time at: Hour = {0} - Minute = {1}", e.SignalTime.Hour, e.SignalTime.Minute);
}
}
catch (Exception ex)
{
OnceADayTimer.Enabled = true;
log.Error(ex.ToString());
}
OnceADayTimer.Start();
}
}
The beef of the method is in the e.SignalTime.Minute/Hour check.
There are hooks in there for testing, etc. but this is what your elapsed timer could look like to make it all work.
As others already wrote, a timer is the best option in the scenario you described.
Depending on your exact requirements, checking the current time every minute may not be necessary.
If you do not need to perform the action exactly at midnight, but just within one hour after midnight, you can go for Martin's approach of only checking if the date has changed.
If the reason you want to perform your action at midnight is that you expect a low workload on your computer, better take care: The same assumption is often made by others, and suddenly you have 100 cleanup actions kicking off between 0:00 and 0:01 a.m.
In that case you should consider starting your cleanup at a different time. I usually do those things not at clock hour, but at half hours (1.30 a.m. being my personal preference)
I would suggest that you use a timer, but set it to check every 45 seconds, not minute. Otherwise you can run into situations where with heavy load, the check for a particular minute is missed, because between the time the timer triggers and the time your code runs and checks the current time, you might have missed the target minute.
You can also try the TaskSchedulerLibrary here http://visualstudiogallery.msdn.microsoft.com/a4a4f042-ffd3-42f2-a689-290ec13011f8
Implement the abstract class AbstractScheduledTask and call the ScheduleUtilityFactory.AddScheduleTaskToBatch static method
For those that found the above solutions not working, it's because you may have a this inside your class, which implies an extension method which, as the error message says, only makes sense on a non-generic static class. Your class isn't static. This doesn't seem to be something that makes sense as an extension method, since it's acting on the instance in question, so remove the this.
Try this:
public partial class Service : ServiceBase
{
private Timer timer;
public Service()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
SetTimer();
}
private void SetTimer()
{
if (timer == null)
{
timer = new Timer();
timer.AutoReset = true;
timer.Interval = 60000 * Convert.ToDouble(ConfigurationManager.AppSettings["IntervalMinutes"]);
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
timer.Start();
}
}
private void timer_Elapsed(object source, System.Timers.ElapsedEventArgs e)
{
//Do some thing logic here
}
protected override void OnStop()
{
// disposed all service objects
}
}

Accurate method to track time

For my application, I've to track the time change, to "smooth" the time change.
A system time change can occurs for several reasons:
The user change its system time
The OS NTP Server updates the local time
...
So actually we have a "TimeProvider", which provide to the whole application the current time.
The goal is to detect if a time shift occurs and correct our local time smoothly(like, if we have a "time jump" of one hour, correct 100ms every second until this is fully corrected).
Here is basically what I've to provide the time(please note that currently I absolutely don't smooth the time change, but not my current issue)
internal class TimeChange : IDisposable
{
private readonly Timer _timer;
private readonly Stopwatch _watch = new Stopwatch();
private DateTime _currentTime;
public DateTime CurrentTime
{
get { return _currentTime + _watch.Elapsed; }
}
public TimeChange()
{
_timer = new Timer(1000);
_timer.Elapsed += OnTimerElapsed;
_timer.Start();
_watch.Start();
_currentTime = DateTime.UtcNow;
}
public void Dispose()
{
_timer.Stop();
_timer.Elapsed -= OnTimerElapsed;
}
private void OnTimerElapsed(object sender, ElapsedEventArgs e)
{
DateTime currentTime = DateTime.UtcNow;
TimeSpan timeDerivation = currentTime - _currentTime - _watch.Elapsed;
_watch.Restart();
_currentTime = currentTime;
Console.WriteLine("Derivation: " + timeDerivation.TotalMilliseconds + "ms");
}
}
But when doing some test, I noticed that I've differences even without doing anything on my local time. Not huge differences(<1ms), but still:
Press enter to stop
Derivation: -0.1367ms
Derivation: 0.9423ms
Derivation: 0.0437ms
Derivation: 0.0617ms
Derivation: 0.0095ms
Derivation: 0.0646ms
Derivation: -0.0149ms
And this is derivation for 1 second, if I just replace the 1000ms by 10000ms, I quickly have a time derivation between 1ms and 0.5ms.
So my question(Finally :P):
Why between two Utc.DateTime gave me so much differences? They are both based on clock Tick no?
Isn't there a way to get this time shift more precisely ?
No they are not both based on clock tick. Stopwatch maybe either high or low res. If low res, then it uses DateTime.UtcNow underneith. Unfortuantely you cannot choose if it's high or low, so:
Create own "Stopwatch" that always uses DateTime.UtcNow underneith.
EDIT
That's a stupid suggestion in (2.), you obviously need to avoid DateTime.UtcNow as that's what you are trying to correct. I suggest you look at working in ticks, by which I mean 1/10000 of a second, to match high-res Stopwatch. This is because TimeSpan is only accurate to 1/1000 of a second.
Number 1. in more detail:
Stopwatch uses this method:
public static long GetTimestamp()
{
if (!Stopwatch.IsHighResolution)
{
DateTime utcNow = DateTime.UtcNow;
return utcNow.Ticks; //There are 10,000 of these ticks in a second
}
else
{
long num = (long)0;
SafeNativeMethods.QueryPerformanceCounter(out num);
return num; //These ticks depend on the processor, and
//later will be converted to 1/10000 of a second
}
}
But like I say, IsHighResolution appears to be not settable and as a static applies system wide anyway, so write your own.

Synchronizing Forms.Timer and Diagnostics.Stopwatch

I have a function (say foo())that will be called from time to time with a variable interval. When it is called, it checks the time and takes an action accordingly.
I have done this in the following way:
A Forms.Timer object invokes the function when required
A Diagnostics.Stopwatch object is used within the function for the purpose of determining the time and deciding what to do.
However I have the following problem: when foo() is called by Timer's callback, the ElapsedMilliseconds value of stopwatch object is usually lower than expected. For example, timer is set to 1000 so after 1000 ms foo() is called, but within foo() body ElapsedMilliseconds return 900 therefore foo behaves as if the elapsed time was 900 (although it should take the action A because 1000 ms actually elapsed, it does not)
How can I synchronize timer and stopwatch in such case that ElapsedMilliseconds have a consistent value with timer?
EDIT: Some Code
Some sample code to explain what is my problem:
//foo is the function that is called by timer's callback
public void foo()
{
//Let's see what time it is:
long currentTime = stopwatch.ElapsedMilliseconds();
Item = getCurrentItem(currentTime);
Item.Draw();
}
//this is the callback of timer
private void timer1_Tick(object sender, EventArgs e)
{
//set the timer for next time
timer1.Interval = Intervals[periodIdx++];
foo();
}
This is supposed to draw something else each time when an interval is completed, however since ElapsedMilliseconds return an earlier value than timer claims, although the interval is over, next item isn't drawn
You get the big difference because you start the timer somewhere within the 1/64 second interval. You'll get better results with this:
private void StartTimers() {
int tick = Environment.TickCount;
while (Environment.TickCount == tick) Thread.Sleep(0);
timer1.Enabled = true;
stopwatch.Start();
}
Where the while() loop improves the odds that the timer gets started at the start of a 1/64 timer tick. Just improves, no guarantees. And you can't do anything about the Tick event firing late, it entirely depends on the responsiveness of your UI thread. It is however always late. Don't use this code, write your code so you don't care that these timers are not in sync. You may have to reduce the timer's Interval to accomplish that, it isn't clear from the question.
You aren't going to have much success with this approach. You're not starting each timer at the exact same time and you're not checking them at the exact same time (there some passage of time between the Timer firing it's event and your code querying the Stopwatch).
Pick a single timer and base everything off of it if you want things in sync. For example, if you want to go with the Forms.Timer, in your event handler for it just increment a counter variable - that will tell you how many times your handler has been called and, effectively, how much time the Forms.Timer says has passed. Here's an example (I'll leave it to you to handle the case of the timer ticking long enough that the counter exceeds long.MaxValue)
public void foo()
{
Item = getCurrentItem(totalElapsed);
Item.Draw();
}
long totalElapsed = 0;
private void timer1_Tick(object sender, EventArgs e)
{
totalElapsed += timer1.Interval;
//set the timer for next time
timer1.Interval = Intervals[periodIdx++];
foo();
}

Synchronizing a service with a timer

I'm trying to write a service in c# that should be run on a given interval (a timeout) from a given date. If the date is in the future the service should wait to start until the date time is reached.
Example:
If I set a timeout to be 1 hour from 21:00:00 I want the program to run every hour
If I set a timeout to be 1 hour from 3999.01.01 21:00:00 I want the program to until date and from then run each hour
I have sort of achieved that with the following code, but it has some problems!
When I install the service (with installutil) the service is marked as starting because of the 'Thread.Sleep()'. This service appears to be hanging and is "installing" until started.
The code inside 'ServiceTimer_Tick()' might take longer than the expected timeout. How can I prevent the timer stack from increasing if that happens?
Alternatives I've thought of :
include using the 'timeout.Interval' first time and then resetting it subsequent calls, but it doesn't feel right.
I've also considered ditching the entire service idea and compile it as a executable and set up a scheduled tasks.
Shortened example:
public Service()
{
_timeout = new TimeSpan(0,1,0,0);
_timer = new System.Timers.Timer();
_timer.Interval = _timeout.TotalMilliseconds;
_timer.Elapsed += new ElapsedEventHandler(ServiceTimer_Tick);
}
private void ServiceTimer_Tick(object sender, System.Timers.ElapsedEventArgs e)
{
lock (_obj)
{
// Stuff that could take a lot of time
}
}
public static void Main()
{
Run(new Service());
}
protected override void OnStart(string[] args)
{
long current = DateTime.Now.Ticks;
long start = new DateTime(2010,9,15,21,0,0).Ticks;
long timeout = _timeout.Ticks;
long sleep;
if (current > start)
sleep = timeout - ((current % timeout)) + (start % timeout);
else
sleep = start - current;
Thread.Sleep(new TimeSpan(sleep));
_timer.AutoReset = true;
_timer.Enabled = true;
_timer.Start();
}
This is easier with a System.Threading.Timer. You can tell it how long to wait before the first tick, and then how often to tick after that.
So, if you wanted to wait 2 days before starting, and then do something once per hour, you'd write:
Timer MyTimer = new Timer(TimerCallback, null, TimeSpan.FromHours(48), TimeSpan.FromHours(1));
That said, if this is something that only has to run once per hour, then it sounds like what you really want is an executable that you then schedule with Windows Task Scheduler.
You can use a System.Threading.Timer. It supports both a dueTime and a period which is just what you need.
you have to move the timer logic to a separate thread that you spawn from your OnStart routine. Then your logic cannot interfere with the SCM and the service will start normally.
Edit: Just to elaborate - for this task I don't think timers work very well, since you are not taking clock corrections into account which could lead to a skew (or even be incorrect if the user manually changes the clock time). That's why comparing to the clock time in small intervals is imo preferred.
The Run routine of that thread could look like this:
public void run()
{
while (processing)
{
//initiate action on every full hour
if (DateTime.Now.Second == 0 && DateTime.Now.Minute == 0)
{
//Do something here
DoSomething();
//Make sure we sleep long enough that datetime.now.second > 0
Thread.Sleep(1000);
}
Thread.Sleep(100);
}
}

Categories

Resources