Launch a program every 12 hours - c#

I want to launch a method in a program every 12 hours.
What do I have to do ?
Do I have to use a Timer to doing this ?
I have this code :
aTimer = new System.Timers.Timer(1000); //One second, (use less to add precision, use more to consume less processor time
int lastHour = DateTime.Now.Hour;
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
aTimer.Start();
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
if(lastHour < DateTime.Now.Hour || (lastHour == 23 && DateTime.Now.Hour == 0))
{
lastHour = DateTime.Now.Hour;
YourImportantMethod(); // Call The method with your important staff..
}
}
Can I adapt it to launch my program every 12 hours ?

A simple solution with async/await:
private static async void RepeatedAction()
{
TimeSpan delay = TimeSpan.FromHours(12);
while (true)
{
await Task.Delay(delay);
YourImportantMethod();
}
}

Use System.Threading.Timer
var start = TimeSpan.Zero;
var period = TimeSpan.FromHours(12);
var timer = new System.Threading.Timer((e) =>
{
YourImportantMethod();
}, null, start, period);

You can use Cron Jobs for this situation
Here is url check and implement. In corn job you can set when your program run

Related

Execute scheduled Task only once

I was trying to Code some simple scheduled Task, which should be executed every full minute (aka when seconds are at 0) but somehow it got messed up. Instead of only doing its job once, it does it over and over as long as the seconds are at 0.
I tried to prevent that by using a bool indicator, but that didnt work.
Hier is my Code example:
static void Main()
{
bool now = true;
while (true)
{
if (DateTime.Now.Second == 0 && now == true)
{
Console.WriteLine("now is: " + DateTime.Now);
now = false;
}
else
{
now = true;
}
}
}
I would prefer to not use sleeps or delays and would like to schedule it by actual time.
Is there an easy way to solve this?
Keep track of your current time and your next run time by changing your code to something like
static void Main(string[] args)
{
var now = DateTime.Now;
var nextRunTime = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, 0).AddMinutes(1);
while (true)
{
var currentTime = DateTime.Now;
if (currentTime >= nextRunTime)
{
Console.WriteLine(currentTime);
nextRunTime = nextRunTime.AddMinutes(1);
}
}
}

How can i run do while for specific time period c#

I have below code which will run for infinite time period but I'm going to take time as input from user.
So if user enter 15mits I want to run this code for 15 mits.
Yes I can compare the DateTime.Now with 15mits but is there any other efficient way to do so ? As this will be my multi threading application.
private static async void SendDeviceToCloudMessagesAsync(string deviceid , string deviceKey)
{
deviceClient = DeviceClient.Create("HOSTNAME", new DeviceAuthenticationWithRegistrySymmetricKey(deviceid, deviceKey), Microsoft.Azure.Devices.Client.TransportType.Mqtt);
double minTemperature = 20;
double minHumidity = 60;
int messageId = 1;
Random rand = new Random();
do
{
double currentTemperature = minTemperature + rand.NextDouble() * 15;
double currentHumidity = minHumidity + rand.NextDouble() * 20;
var telemetryDataPoint = new
{
messageId = messageId++,
deviceId = deviceid,
temperature = currentTemperature,
humidity = currentHumidity
};
var messageString = JsonConvert.SerializeObject(telemetryDataPoint);
var message = new Microsoft.Azure.Devices.Client.Message(Encoding.ASCII.GetBytes(messageString));
message.Properties.Add("temperatureAlert", (currentTemperature > 30) ? "true" : "false");
await deviceClient.SendEventAsync(message);
Console.WriteLine("{0} > Sending message: {1}", DateTime.Now, messageString);
await Task.Delay(1000);
} while (true);
}
You could check out System.Timers.Timer. You create an instance of it setting the interval in the constructor, then write a method to handle the Elapsed event.
// Create a timer with a two second interval.
var aTimer = new System.Timers.Timer(2000);
// Hook up the Elapsed event for the timer.
aTimer.Elapsed += OnTimedEvent // Name this whatever you want and put code here;
aTimer.AutoReset = true;
aTimer.Enabled = true;
All you have to do now is write the Elapsed event handler... OnTimedEvent in this case. Note that this method must have this signature:
private static void Object source, ElapsedEventArgs e)
try to replace your code against
await Task.Delay(TimeSpan.FromSeconds(1000));

Timer to exact time by seconds

I'm trying to run an infinite loop in parallel with the other code, that is executed once a specific time acheived by SECOND.
In the below code I'm trying to touch the exact midnight time, that is: 00 hh: 00 mm: 00 sec
using System; // for Date/Time
using System.Threading.Tasks; // for Parallel
public class Program
{
public static void Main(string[] args)
{
Parallel.Invoke(
() =>
{
Console.WriteLine("Begin first task...");
}, // close first Action
async () =>
{
Console.WriteLine("Begin second task...");
var midNight = "00:00:00";
while (true)
{
TimeSpan duration = DateTime.Parse(midNight).Subtract(DateTime.Now);
Console.WriteLine("looping at: {0:00} Days, {1:00} Hours, {2:00} Minutes, {3:00} Seconds, {4:00} Milliseconds",
duration.Days, duration.Hours, duration.Minutes, duration.Seconds, duration.Milliseconds);
if(duration.Days >= 1)
await Task.Delay(8640000);
else if(duration.Hours >= 1)
await Task.Delay(360000);
else if(duration.Minutes >= 1)
await Task.Delay(60000);
else
await Task.Delay(1000);
if(duration == TimeSpan.Zero) {
Console.WriteLine("It is time... midnight is {0}", DateTime.Now);
} // close second Action `the async task`
) // end of Parallel.Invoke
} // End of Main
} // End of Program
I was able to the await statement work correctly to reach the required point, but the lock the condition if(duration == TimeSpan.Zero) never become true
First of all your program can't work as you showed because your TimeSpan duration = DateTime.Parse(midNight).Subtract(DateTime.Now); never will be positive. Second you main function will return almost immediately. Anyway you can try my solution for your problem:
using System;
using System.Threading;
using System.Threading.Tasks;
public class Program
{
public static void Main(string[] args)
{
Parallel.Invoke(
() =>{Console.WriteLine("Begin first task...");},
async () =>
{
Console.WriteLine("Begin second task...");
DateTime startDate = DateTime.Today;
while (true)
{
TimeSpan duration = DateTime.Now.Subtract(startDate);
Console.WriteLine("looping at: {0:00} Days, {1:00} Hours, {2:00} Minutes, {3:00} Seconds, {4:00} Milliseconds",
duration.Days, duration.Hours, duration.Minutes, duration.Seconds, duration.Milliseconds);
int delay = (int)(DateTime.Today.AddDays(1.0).Subtract(DateTime.Now).TotalMilliseconds/2);
await Task.Delay(delay>0?delay:0);
if(duration.Days >= 1)
{
Console.WriteLine("It is time... midnight is {0}", DateTime.Now);
startDate = DateTime.Today;
}
}
}
);
}
}
This will not provide you super precision as on normal PC you can't get it (you could use IRQ to get better accuracy but solution like that is far more complex).
Also as prof of concept link to 10s version.
At time version:
using System;
using System.Threading;
using System.Threading.Tasks;
public class Program
{
public static void Main(string[] args)
{
Parallel.Invoke(
async () =>
{
Console.WriteLine("Begin second task...");
TimeSpan eventTime = new TimeSpan(0,18,16,53,123); //set when run event (ex. 18:16:53.123)
DateTime endDate = DateTime.Today.Add(eventTime);
if(endDate<DateTime.Now) endDate = endDate.AddDays(1.0);
while (true)
{
TimeSpan duration = endDate.Subtract(DateTime.Now);
Console.WriteLine("looping at: {0:00} Days, {1:00} Hours, {2:00} Minutes, {3:00} Seconds, {4:00} Milliseconds", duration.Days, duration.Hours, duration.Minutes, duration.Seconds, duration.Milliseconds);
if(duration.TotalMilliseconds <= 0.0)
{
Console.WriteLine("It is time... {0}", DateTime.Now);
endDate = endDate.AddDays(1.0);
continue;
}
int delay = (int)(duration.TotalMilliseconds/2);
await Task.Delay(delay>0?delay:0);
}
}
);
Thread.Sleep(6000);
}
}
I was able to do it by changing the condition from:
if(duration == TimeSpan.Zero)
to:
if(duration.Days == 0 && duration.Hours == 0 && duration.Minutes == 0 && duration.Seconds == 0)
and to avoid the double occurrence of the event, i added another await level, so the new one became like:
if(duration.Days >= 1)
await Task.Delay(8640000);
else if(duration.Hours >= 1)
await Task.Delay(360000);
else if(duration.Minutes >= 1)
await Task.Delay(60000);
else if(duration.Seconds >= 1)
await Task.Delay(1000);
else
await Task.Delay(500);
I tried adding the if(duration.Milliseconds >= 1) await(1) but did not work, my output became as shown below:
The problem is that in your case, the duration is never zero, it goes from plus some milliseconds to minus some milliseconds.
What I would do: If duration is less than one second, wait for duration and then just assume it's the right time. In code:
if (duration.Days >= 1)
await Task.Delay(8640000);
else if (duration.Hours >= 1)
await Task.Delay(360000);
else if (duration.Minutes >= 1)
await Task.Delay(60000);
else if (duration.Seconds >= 1)
await Task.Delay(1000);
else
{
// defensive check in case duration is already negative
// this should not normally happen, but is still possible
if (duration > TimeSpan.Zero)
await Task.Delay(duration);
Console.WriteLine("It is time... midnight is {0}", DateTime.Now);
}
This won't give you millisecond accuracy, but it should be the right second, under normal circumstances.

Windows service and timer in C#

I need help to write a windows service with a timer that can call 3 different function(events) in 3 different times every day.
Some code example please. Thank you.
private System.Timers.Timer timer;
protected override void OnStart(string[] args)
{
this.timer1 = new System.Timers.Timer(60000);
this.timer1.AutoReset = true;
this.timer1.Elapsed += new System.Timers.ElapsedEventHandler(this.timer1_Elapsed);
this.timer1.Start();
}
private DateTime _lastRun1 = DateTime.Now.AddDays(-1);
private DateTime _lastRun2 = DateTime.Now.AddDays(-1);
private DateTime _lastRun3 = DateTime.Now.AddDays(-1);
private void timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (_lastRun.Date < DateTime.Now.Date && DateTime.Now.Hour == 13)
{
//call functionX
DateTime _lastRun1 = DateTime.Now.AddDays(1);
}
if (_lastRun.Date < DateTime.Now.Date && DateTime.Now.Hour == 14)
{
//call functionY
DateTime _lastRun2 = DateTime.Now.AddDays(1);
}
if (_lastRun.Date < DateTime.Now.Date && DateTime.Now.Hour == 16)
{
//call functionXY
DateTime _lastRun3 = DateTime.Now.AddDays(1);
}
}
Why not just write 3 distinct applications and let the Windows task scheduler execute them at the appropriate times? This will probably be a lot easier than trying to get your own scheduling logic right, which can often be more complicated than you'd expect.

Calling a method every x minutes

I want to call some method on every 5 minutes. How can I do this?
public class Program
{
static void Main(string[] args)
{
Console.WriteLine("*** calling MyMethod *** ");
Console.ReadLine();
}
private MyMethod()
{
Console.WriteLine("*** Method is executed at {0} ***", DateTime.Now);
Console.ReadLine();
}
}
var startTimeSpan = TimeSpan.Zero;
var periodTimeSpan = TimeSpan.FromMinutes(5);
var timer = new System.Threading.Timer((e) =>
{
MyMethod();
}, null, startTimeSpan, periodTimeSpan);
Edit - this answer is out of date. See https://stackoverflow.com/a/70887955/426894
I based this on #asawyer's answer. He doesn't seem to get a compile error, but some of us do. Here is a version which the C# compiler in Visual Studio 2010 will accept.
var timer = new System.Threading.Timer(
e => MyMethod(),
null,
TimeSpan.Zero,
TimeSpan.FromMinutes(5));
Update .NET 6
For most use cases in dotnet 6+, you should use the PeriodicTimer:
var timer = new PeriodicTimer(TimeSpan.FromSeconds(10));
while (await timer.WaitForNextTickAsync())
{
//Business logic
}
This has several advantages, including async / await support, avoiding memory leaks from callbacks, and CancelationToken support
Further Reading
API proposal: Modern Timer API
Execute specified function every X seconds
Why there are 5 Versions of Timer Classes in .NET?
A New Modern Timer API In .NET 6 - PeriodicTimer
Start a timer in the constructor of your class.
The interval is in milliseconds so 5*60 seconds = 300 seconds = 300000 milliseconds.
static void Main(string[] args)
{
System.Timers.Timer timer = new System.Timers.Timer();
timer.Interval = 300000;
timer.Elapsed += timer_Elapsed;
timer.Start();
}
Then call GetData() in the timer_Elapsed event like this:
static void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
//YourCode
}
Example of using a Timer:
using System;
using System.Timers;
static void Main(string[] args)
{
Timer t = new Timer(TimeSpan.FromMinutes(5).TotalMilliseconds); // Set the time (5 mins in this case)
t.AutoReset = true;
t.Elapsed += new System.Timers.ElapsedEventHandler(your_method);
t.Start();
}
// This method is called every 5 mins
private static void your_method(object sender, ElapsedEventArgs e)
{
Console.WriteLine("...");
}
I've uploaded a Nuget Package that can make it so simple, you can have it from here ActionScheduler
It supports .NET Standard 2.0
And here how to start using it
using ActionScheduler;
var jobScheduler = new JobScheduler(TimeSpan.FromMinutes(8), new Action(() => {
//What you want to execute
}));
jobScheduler.Start(); // To Start up the Scheduler
jobScheduler.Stop(); // To Stop Scheduler from Running.
Use a Timer. Timer documentation.
Using a DispatcherTimer:
var _activeTimer = new DispatcherTimer {
Interval = TimeSpan.FromMinutes(5)
};
_activeTimer.Tick += delegate (object sender, EventArgs e) {
YourMethod();
};
_activeTimer.Start();
If you need more complicated time executions such as linux cron, you can use NCrontab.
I use NCrontab in production for long time and it works perfect!
Nuget
How to use:
* * * * *
- - - - -
| | | | |
| | | | +----- day of week (0 - 6) (Sunday=0)
| | | +------- month (1 - 12)
| | +--------- day of month (1 - 31)
| +----------- hour (0 - 23)
+------------- min (0 - 59)
using NCrontab;
//...
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
// run every 5 minutes
var schedule = CrontabSchedule.Parse("*/5 * * * *");
var nextRun = schedule.GetNextOccurrence(DateTime.Now);
logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
do
{
if (DateTime.Now > nextRun)
{
logger.LogInformation("Sending notifications at: {time}", DateTimeOffset.Now);
await DoSomethingAsync();
nextRun = schedule.GetNextOccurrence(DateTime.Now);
}
await Task.Delay(1000, stoppingToken);
} while (!stoppingToken.IsCancellationRequested);
}
Add seconds if you need:
// run every 10 secs
var schedule = CrontabSchedule.Parse("0/10 * * * * *", new CrontabSchedule.ParseOptions { IncludingSeconds = true });
It can be achieved by applying while loop and calling Thread.Sleep at the end of the loop.
while (true)
{
//Your code
Thread.Sleep(5000);
}
Make sure to include using System.Threading.
while (true)
{
Thread.Sleep(60 * 5 * 1000);
Console.WriteLine("*** calling MyMethod *** ");
MyMethod();
}

Categories