I have this if condition where I need to do some stuff if the difference is 15 min or so
if (DateTime.UtcNow - x.Timestamp == TimeSpan.FromMinutes(15))
{
//Do something
}
The above condition never satisfies when I check with == but when I do >= it gets into the condition but that's not what I need, I want 15 min or so difference.
Can someone explain this behavior?
Sample Data:
x = 2/17/2020 8:45:17 PM
//I cannot comment on the above answer i dont have enough Rep
I think a better solution for a time trigger to do something would be like so:
static System.Timers.Timer _t = new System.Timers.Timer();
void Init()
{
//Start a timer trigger every 300000 milliseconds = 5 minutes
_t.Interval = 300000;
_t.Elapsed += fiveMinutesElapsed;
_t.Enabled = true;
}
public void fiveMinutesElapsed()
{
t.Enabled = false;
//Do Something
t.Enabled = true;
}
Can someone explain this behavior?
Yes: It is very unlikely that the elapsed time calculated from DateTime.Now is exactly equal to your specified TimeSpan.
From your comments, it seems that you want to periodically check if it's time to do something. One easy way to do this is to use a Stopwatch to keep track of the amount of time that has elapsed since the last time you did the thing:
using System;
using System.Diagnostics;
using System.Threading;
namespace ConsoleApp1
{
class Program
{
static void Main()
{
throttleTimer.Start();
// This loop simulates your periodic check to see if the action
// needs to be performed:
while (true)
{
doActionIfTimeElapsed(TimeSpan.FromSeconds(5));
Thread.Sleep(1000); // Simulate checking every 1 second or so.
}
}
static Stopwatch throttleTimer = new Stopwatch();
static void doActionIfTimeElapsed(TimeSpan period)
{
if (throttleTimer.Elapsed <= period)
return;
doAction();
throttleTimer.Restart();
}
static void doAction()
{
Console.WriteLine("Doing the action.");
}
}
}
This sample program will perform doAction() whenever you call doActionIfTimeElapsed() and more than 5 seconds has elapsed since the last time it called doAction().
Alternatively, if you want to perform an action after every N seconds without having to call a method to periodically check if the action should be performed, then you can use a System.Threading.Timer instead.
Option 1:
If x.Timestamp is something you can reset (not a server-/client-side readonly value), then use >= (or > as = is less likely to ever happen) and reset x.Timestamp to the current time. Also, check this answer for determining relative time.
Option 2:
If you just want to raise a function in every 15 minutes, you have the answer here.
Note that 3 different timers exist, if you will need one that operate within seconds or milliseconds, you may want to avoid overlapping: which is (only?) possible with System.Timers.Timer via its Enabled property.
Option 3:
If you want to raise a function inside a while loop in every 15 minutes, I propose to use a StopWatch.
var watch = new StopWatch();
watch.Start();
while(...)
{
if (watch.Elapsed > TimeSpan.FromMinutes(15))
{
// do your stuff
watch.Restart();
}
}
Related
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
}
}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I'm trying to make a program whereby it does something every x minutes. I have been experimenting with the Stopwatch function but it don't seem to run the code I want when the time is up.
Here's my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Threading;
namespace Testing
{
class Program
{
static void Main(string[] args)
{
Stopwatch testing = new Stopwatch();
testing.Start();
Thread.Sleep(6001);
TimeSpan ts = testing.Elapsed;
int timer = Convert.ToInt32(String.Format("{0}", ts.Seconds));
Console.Write(timer);
while (testing.Elapsed < TimeSpan.FromMinutes(8))
{
timer = Convert.ToInt32(String.Format("{0}", ts.Seconds));
if (timer % 60 == 0)
{
//run x code every 1 minutes
Console.WriteLine("1 min" + timer);
}
timer = Convert.ToInt32(String.Format("{0}", ts.Seconds));
if (timer % 120 == 0)
{
//run x code every 2 minutes
Console.WriteLine("2 min" + timer);
}
}
testing.Stop();
}
}
}
Stopwatch is a high-performance timer (usually with 100ns resolution) - it is entirely inappropriate for what you're trying to do. Stopwatch is used to measure time by taking snapshots of a system counter and then calculating the difference.
Since most of a scheduler's job is to wait until a job needs to be done, implementing a scheduler with a tight loop is extremely inefficient - the system is using CPU resources to decide to not do anything for most of the time.
To properly implement a scheduler (if that's what you're trying to do), look into using ManualResetEvent with a timeout option.
Using an event puts your current thread to sleep (so it's not using system resources while it's doing nothing) and when the timeout expires, the event is triggered and the code can call the function that you're trying to schedule.
If you want nothing else than a simple timer that tells you when an interval elapsed, use System.Timers.Timer instead: this makes it much simpler to schedule a callback (the Elapsed event is called when the timer expires) and you don't have to run a loop during the wait.
Edit:
If you simply want to call a callback function periodically, a simple timer is easier to hook up than an event. Here's a code sample using System.Timer (not my code, I copy & pasted this from MSDN, linked above):
private static Timer m_oTimer;
public static void Main ()
{
m_oTimer = new System.Timers.Timer ( 2 * 1000 * 60 ); // 2 minutes
m_oTimer.Elapsed += OnTimedEvent; // Timer callback
m_oTimer.Enabled = true; // Start timer
// Wait here (you can do other processing here, too)
Console.WriteLine ( "Press the Enter key to exit the program... " );
Console.ReadLine ();
Console.WriteLine ( "Terminating the application..." );
}
private static void OnTimedEvent ( Object source, ElapsedEventArgs e )
{
// This is called on a separate thread; do periodic processing here
Console.WriteLine ( "The Elapsed event was raised at {0}", e.SignalTime );
}
As suggested by xxbbcc, here's an implementation using ManualResetEvent.WaitOne() with a TimeOut:
static void Main(string[] args)
{
int TimeOut = (int)TimeSpan.FromMinutes(2).TotalMilliseconds;
System.Threading.ManualResetEvent mreDuration = new System.Threading.ManualResetEvent(false);
Task.Run(() => {
System.Threading.Thread.Sleep((int)TimeSpan.FromMinutes(30).TotalMilliseconds);
mreDuration.Set();
});
while(!mreDuration.WaitOne(TimeOut))
{
Console.WriteLine("Two Minutes...");
}
Console.WriteLine("Thirty Mintues!");
Console.ReadLine();
}
You should use Timer. If you want timer to stop running after, let's say, 'y' minutes, then you just store the start time in a variable and write the Timer.Stop() function so that it get executed after 'y' minutes (hint: write it in timer_tick event). Time period of the timer should be HCF of all x's and y. Remember to set time period in miliseconds.
I am coding a C# WinForms program that I want to have running in the background 24/7. In an XML file, I'm pulling a time. For example: 3:30:00 PM. When I then display this time after parsing it, it comes out as 1/15/2014 3:30:00 PM.
What my question is, based on this XML value, how can I have it so that, at 3:30:00 PM every day, a Timer object or something displays a message box or some other action?
Your idea of using a Timer is good. You could use either the Winforms Timer or System.Timers.Timer. In this case, I will refer to System.Timers.Timer as I have some code I can base this answer off of.
Anyway, just assign it an Interval and give an event to fire via Elapsed. Then in the code that Elapsed calls, put in your action code. Finally, start the timer wherever you need it and try running it.
If you are using a DateTime to hold the file data, then you will need to either create a constant number of milliseconds until the next day (not recommended), or do some math using TimeSpans (hint: use the constructor to get the time). The TimeSpan contains a property called 'TotalMilliseconds' that you can use as the Interval.
I hope this points you in the right direction.
That is a console application that executes a job at a fixed time every day
using System;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
public static void Main()
{
Timer t = new Timer(TimerCallback, null, 0, 2000);
// Wait for the user to hit <Enter>
Console.ReadLine();
}
private static void TimerCallback(Object o)
{
Console.WriteLine("In TimerCallback: " + DateTime.Now);
DateTime s = DateTime.Now;
TimeSpan ts = new TimeSpan(23, 27, 0);
s = s.Date + ts;
if (DateTime.Now > s && !fired)
{
Console.WriteLine("Do the Job");
fired = true;
}
else if (DateTime.Now < s)
{
fired = false;
}
}
private static bool fired = false;
}
}
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);
}
}
I'm trying to invoke a method f() every t time, but if the previous invocation of f() has not finished yet, wait until it's finished.
I've read a bit about the available timers but couldn't find any good way of doing what I want, save for manually writing it all. Any help about how to achieve this will be appreciated, though I fear I might not be able to find a simple solution using timers.
To clarify, if t is one second, and f() runs the arbitrary durations I've written below, then:
Step Operation Time taken
1 wait 1s
2 f() 0.6s
3 wait 0.4s (because f already took 0.6 seconds)
4 f() 10s
5 wait 0s (we're late)
6 f() 0.3s
7 wait 0.7s (we can disregard the debt from step 4)
Notice that the nature of this timer is that f() will not need to be safe regarding re-entrance, and a thread pool of size 1 is enough here.
Use a System.Threading.Timer. Initialize it with a period of Timeout.Infinite so it acts like a one-shot timer. When f() completes, call its Change() method to recharge it again.
You could just use a 'global' level var (or more likely, a public property in the same class as f()) which returns true if f() is already running.
So if f() was in a class named TimedEvent, the first thing f() would do is set Running true
That way your timer fires every second, then launches the timed event if it isnt already running
if (!timedEvent.Running) timedEvent.f()
You commented that f() wouldnt repeat immediately if it took longer than the timer interval. Thats a fair point. I would probably include logic like that inside f() so that Running stays true. So it would look something like this:
public void f(int t) // t is interval in seconds
{
this.running = true;
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
do
{
stopwatch.Reset();
// Do work here
} while (stopWatch.Elapsed.Seconds > t); // repeat if f() took longer than t
this.running = false;
}
You can use a non-restarting timer, then manually restart the timer after the method finishes.
Note that this will result in timing that is somewhat different from what you're asking for. (There will always be a gap of t time between invocations)
You could solve that by setting the interval to lastTick + t - Now, and running the method immediately if that's <= 0.
Beware of race conditions if you need to stop the timer.
You cannot get a timer to call you at exactly scheduled intervals. All timers do is call you back no sooner than the requested time.
Some timers are better than others (e.g. Windows.Forms.Timer is very erratic and unreliable compared to System.Threading.Timer)
To stop your timer being called re-entrantly, one approach is to Stop the timer while your method is running. (Depending on the type of timer you use, you either stop it and start it again when your handler exits, or with some timers you can request a single callback rather than repeating callbacks, so each execution of your handler simply enqueues the next call).
To keep the timing relatively even between these calls you can record the time since your handler last executed and use that to calculate the delay until the next event is required. e.g. If you want to be called once per second and your timer completed provcessing at 1.02s, then you can set up the next timer callback at a duration of 0.98s to accomodate the fact that you've already "used up" part of the next second during your processing.
A straightforward solution:
private class Worker : IDisposable
{
private readonly TimeSpan _interval;
private WorkerContext _workerContext;
private sealed class WorkerContext
{
private readonly ManualResetEvent _evExit;
private readonly Thread _thread;
private readonly TimeSpan _interval;
public WorkerContext(ParameterizedThreadStart threadProc, TimeSpan interval)
{
_evExit = new ManualResetEvent(false);
_thread = new Thread(threadProc);
_interval = interval;
}
public ManualResetEvent ExitEvent
{
get { return _evExit; }
}
public TimeSpan Interval
{
get { return _interval; }
}
public void Run()
{
_thread.Start(this);
}
public void Stop()
{
_evExit.Set();
}
public void StopAndWait()
{
_evExit.Set();
_thread.Join();
}
}
~Worker()
{
Stop();
}
public Worker(TimeSpan interval)
{
_interval = interval;
}
public TimeSpan Interval
{
get { return _interval; }
}
private void DoWork()
{
/* do your work here */
}
public void Start()
{
var context = new WorkerContext(WorkThreadProc, _interval);
if(Interlocked.CompareExchange<WorkerContext>(ref _workerContext, context, null) == null)
{
context.Run();
}
else
{
context.ExitEvent.Close();
throw new InvalidOperationException("Working alredy.");
}
}
public void Stop()
{
var context = Interlocked.Exchange<WorkerContext>(ref _workerContext, null);
if(context != null)
{
context.Stop();
}
}
private void WorkThreadProc(object p)
{
var context = (WorkerContext)p;
// you can use whatever time-measurement mechanism you want
var sw = new System.Diagnostics.Stopwatch();
int sleep = (int)context.Interval.TotalMilliseconds;
while(true)
{
if(context.ExitEvent.WaitOne(sleep)) break;
sw.Reset();
sw.Start();
DoWork();
sw.Stop();
var time = sw.Elapsed;
if(time < _interval)
sleep = (int)(_interval - time).TotalMilliseconds;
else
sleep = 0;
}
context.ExitEvent.Close();
}
public void Dispose()
{
Stop();
GC.SuppressFinalize(this);
}
}
How about using delegates to method f(), queuing them to a stack, and popping the stack as each delegate completes? You still need the timer, of course.
A simple thread is the easiest way to achieve this. Your still not going to be certain that your called 'precisely' when you want, but it should be close.... Also you can decide if you want to skip calls that should happen or attempt to catch back up... Here is simple helper routine for creating the thread.
public static Thread StartTimer(TimeSpan interval, Func<bool> operation)
{
Thread t = new Thread(new ThreadStart(
delegate()
{
DateTime when = DateTime.Now;
TimeSpan wait = interval;
while (true)
{
Thread.Sleep(wait);
if (!operation())
return;
DateTime dt = DateTime.Now;
when += interval;
while (when < dt)
when += interval;
wait = when - dt;
}
}
));
t.IsBackground = true;
t.Start();
return t;
}
For the benefit of people who land here searching for "re-entrancy": (I know this may be too late for the original question)
If one is not averse to using open source libraries that already provide for such functionality, I have successfully achieved this through an implementation using Quartz.NET
When you create a job and attach a trigger, you can specify what should be done if a previous trigger has not completed executing it's job