Timer to exact time by seconds - c#

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.

Related

Launch a program every 12 hours

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

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 to make an order in right time C#

first sorry for my bad English
i want to make an order in my program when it come 12:00 AM in my PC
i try with this code
string Time = "00:00 AM";
while (true)
{
if (Time == DateTime.UtcNow.ToString("hh:mm tt"))
{
Console.ForegroundColor = ConsoleColor.Blue;
// Update Days -1 Where Service = 1
sqlCon.exec("update HelperSystem set Days = Days-1 where Service=1 and Days != 0");
Meldung("Updated HelperSystem Table Days -1");
// Update Service = 0 Where Days = 0
sqlCon.exec("update HelperSystem set Service = 0 where Days = 0");
Meldung("Updated HelperSystem Table Service = 0 Where Days = 0");
// Update Days -1 Where Service = 1
sqlCon.exec("update AutoEvent set Days = Days-1 where Service=1 and Days != 0");
Meldung("Updated AutoEvent Table Days -1");
// Update Service = 0 Where Days = 0
sqlCon.exec("update AutoEvent set Service = 0 where Days = 0");
Meldung("Updated AutoEvent Table Service = 0 Where Days = 0");
Console.ResetColor();
Thread.Sleep(120000);
}
Thread.Sleep(1);
}
and when i try with breakpoint return value 12:00 AM but didn't do anything
If you're trying to match times using a formatted string then you should ensure you're comparing against the same format. You should do something like this:
string timeFormat = "hh:mm tt";
string Time = (new DateTime(1970, 1, 1, 0, 0, 0)).ToString(timeFormat); //12:00 AM
while (true)
{
if (Time == DateTime.UtcNow.ToString(timeFormat))
{
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine("Run.");
Console.ResetColor();
Thread.Sleep(120000);
}
Thread.Sleep(1);
}
However, this approach isn't great. You really have nothing ensuring that the process will actually execute at the right time of day to ensure equality works. In this case you'd be very unlucky as it only has to run once in the 60 seconds that the time text is correct, but there is no guarantee. You really should compare against a specific time.
This is better:
DateTime Time = DateTime.UtcNow.AddDays(1.0).Date;
while (true)
{
if (DateTime.UtcNow > Time)
{
Time = DateTime.UtcNow.AddDays(1.0).Date;
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine("Run.");
Console.ResetColor();
}
Thread.Sleep(1);
}
There's no need for the messy Thread.Sleep(120000); in this code.
However, you still have the Thread.Sleep(1); call which is bad.
I'd suggest using a library that has been designed for this kind of thing. Try Microsoft's Reactive Framework (NuGet "System.Reactive") and then you can do this:
IDisposable subscription =
Observable
.Timer(DateTimeOffset.UtcNow.AddDays(1.0).Date, TimeSpan.FromDays(1.0))
.Subscribe(x =>
{
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine("Run.");
Console.ResetColor();
});
When you're closing down your app just call subscription.Dispose(); and it'll cleanly stop.
Change string Time = "4:30 AM"; to "04:30 AM"
public static void Main()
{
string Time = "4:30 AM";
while (true)
{
Console.WriteLine("{0}",DateTime.UtcNow.ToString("hh:mm tt"));
// Prints 04:30 AM - so that is why it does not match 4:30 AM
if (Time == DateTime.UtcNow.ToString("hh:mm tt"))
{
Console.ForegroundColor = ConsoleColor.Blue;
// Update Days -1 Where Service = 1
Console.WriteLine("I am In");
Console.ResetColor();
}
Thread.Sleep(1000);
}
}

How to check thread is sleeping in x second c#

I write application need check if time to checkLogin() sleep over > 30 seconds.
Then, it will break this while loop and continues the program.
My code like this:
while(!Account.checkLogin())
{
Thread.Sleep(1000);
}
How to check like:
while(!Account.checkLogin())
{
Thread.Sleep(1000);
if(Thread.Sleep like 30000)
continues;
}
If I understood the question correctly, you could sum up the iterations and and use them in the termination condition as follows.
int MAX_ITERATIONS = 30;
int NumOfIterations = 0;
while(!Account.checkLogin() && NumOfIterations < MAX_ITERATIONS)
{
Thread.Sleep(1000);
NumOfIterations++;
}
You can just sleep for 30 seconds:
Thread.Sleep(30000);
However that's holding up the thread and stops you doing anything inbetween. I prefer to use a TimeSpan, for example:
DateTime started = DateTime.UtcNow;
while (!Account.checkLogin())
{
TimeSpan ts = DateTime.UtcNow - started;
if (ts.TotalSeconds >= 30)
break;
Thread.Sleep(1000);
}

C# - Close console application when calculations take more time

I wrote app that is doing repeatedly some task every minute. Problem is that sometimes ( inner calculations ( because CPU was busy or because of any reasons) take more than 50 seconds, then I have to close app. "App monitor that is independent application will turn it on again" so that is not a problem. I implemented watchdog which can tell me if time is finished and then shut down my app.
And my question is if I'm doing it correctly. I test this solution for some time and it looks like working ok.
Main program
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace AppTimer
{
class Program
{
public static appScheduler ap = new appScheduler();
static void Main(string[] args)
{
Console.WriteLine("Press ESC to stop");
while (ap.getWatchDogSeconds() < 55)
{
if (Console.KeyAvailable)
{
if (Console.ReadKey(true).Key == ConsoleKey.Escape)
{
break;
}
}
Thread.Sleep(100);
}
Console.WriteLine("Watchdog Fired ....sw finished !!");
Thread.Sleep(2000);
}
/// <summary>
/// Emulation of long calculation process
/// </summary>
public static void doJob()
{
Console.Clear();
Thread.Sleep(5000);
Console.WriteLine("Busy...");
Console.WriteLine("WatchDog Seconds : " + ap.getWatchDogSeconds());
ap.setWatchDogSeconds(40);
Console.WriteLine("Waiting longer than normal...");
Console.WriteLine("WatchDog Seconds : " + ap.getWatchDogSeconds());
Thread.Sleep(5000);
Console.WriteLine("Maybe sth is down !! or too busy");
Console.WriteLine("WatchDog Seconds : " + ap.getWatchDogSeconds());
while (true)
{
Thread.Sleep(200);
}
}
}
}
Below appScheduler class :
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace AppTimer
{
public class appScheduler
{
static readonly object _lockerWD = new object();
static int minutes = 0;
static int seconds = 50;
static int days = 0;
static int hours = 0;
private static Task calculationsTask;
private int watchDogSeconds = 0;
private int maxSecondsForWatchdog = 50;
public appScheduler()
{
startTimer();
startWatchdogTimer();
}
private void ExecuteSeconds()
{
if (seconds == 0)
{
executeRepeatdTask();
}
calculateTime();
showTimerScreen();
}
private void executeRepeatdTask()
{
calculationsTask = Task.Factory.StartNew(() =>
Program.doJob());
}
public void startTimer()
{
var timer = new System.Threading.Timer((e) =>
{
ExecuteSeconds();
}, null, 0, 1000);
}
public void startWatchdogTimer()
{
var timer = new System.Threading.Timer((e) =>
{
ExecuteSecondsWatchDog();
}, null, 0, 1000);
}
private void ExecuteSecondsWatchDog()
{
Trace.WriteLine("Current amount of WD Seconds : " + watchDogSeconds);
increaseWatchDogSeconds();
}
private void showTimerScreen()
{
if ((calculationsTask == null) || (calculationsTask.IsCompleted == true))
{
//making watchdog zero if time is running and we are showing it!!
Console.Clear();
Console.WriteLine("This is software v1.2");
Console.WriteLine(String.Format("Current execution time : {0} days : {1} hours : {2} : minutes : {3} seconds",
days, hours, minutes, seconds));
Console.WriteLine("WatchDog Seconds : " + watchDogSeconds);
setWatchDogSeconds(0);
}
}
private void calculateTime()
{
seconds++;
if (seconds > 59)
{
seconds = 0;
minutes++;
if (minutes > 59)
{
minutes = 0;
hours++;
if (hours > 23)
{
hours = 0;
days++;
}
}
}
}
public int getMinutes()
{
return minutes;
}
public int getWatchDogSeconds()
{
return watchDogSeconds;
}
public void setWatchDogSeconds(int seconds)
{
Monitor.Enter(_lockerWD);
watchDogSeconds = seconds;
Monitor.Exit(_lockerWD);
}
public void increaseWatchDogSeconds()
{
var seconds = getWatchDogSeconds();
setWatchDogSeconds(seconds += 1);
if (seconds > maxSecondsForWatchdog)
{
Trace.WriteLine(string.Format("More than {0} seconds!", maxSecondsForWatchdog)); ;
Environment.Exit(0);
}
}
}
}
I do a great deal of workflow type tasks every day. I have tried to kick off jobs in the past the way you have here. The only time I use Thread.Sleep is to simulate some long running process in a test environment. I would look into using SetTimer. Also using Thread.Sleep in a loop is not going to give you accurate results. Now, that being said, keeping this running is going to be tricky.
Ultimately kicking off jobs on a regular basis is a breeze if you have an SQL server and can set the call up in an SSIS package. Especially if you are are trying to do this in a web application which might just stop running after a period of time. Good Luck

Categories