Schedule a daily event on a program that runs all day - c#

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;
}
}

Related

C# how to check exact time difference in if condition

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();
}
}

Timer resets after 60 seconds

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();
}

reset the timer on second call

I am bit New here ...and learning Threading.Timer ... I have a timer in Window Service which fires a function at 16:48:00 ..I just want to Fire the Timer Again at 21:00:00 PM ...then 22:00:00 ...there is no fix timer interval between the timeslots
here is My Code what I have Tried:
public partial class ASMSService1 : ServiceBase
{
private Timer myTimer;
private DateTime inputDate;
private DateTime yesterday;
private DateTime today;
public ASMSService1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
inputDate = DateTime.Today;
today = DateTime.Today;
yesterday = today.AddDays(-1);
//time is Set here
SetTimer(16, 48, 00);
}
private void SetTimer(int hours, int minutes, int seconds)
{
inputDate = DateTime.Today.AddHours(hours).AddMinutes(minutes).AddSeconds(seconds);
String date1 = inputDate.TimeOfDay.ToString();
if (DateTime.Now > inputDate)
{
inputDate = inputDate.AddDays(1);
}
if (date1.CompareTo("16:48:00") == 0)
{
myTimer = new System.Threading.Timer(new TimerCallback(FirstSlotOperations));
myTimer.Change((int)(inputDate - DateTime.Now).TotalMilliseconds, Timeout.Infinite);
}
}
private void FirstSlotOperations(object e)
{
//some operation
//Need to reset the Timer at 21:00:00
}
}
I have found the timer.change From MSDN article ..But I am not sure How to implement it in my case
I have Tried Thread.sleep()..But I am looking for some alternative also if possible ..
any suggestion would be Helpful
I think Artyom Kharlamov is right, if you provide more details about what specific functionality do you intend to achieve, there is a better chance to get an answer that is closer to what you need.
My take on what you have currently presented:
If you want the service to perform a specific operation whenever the time of the day is equal to a predefined value (for example 16:48 as per your provided code), i think your approach is kind of complicated since you could achieve this easier by using Scheduled Tasks, which will also cover the case in which you're trying to perform an operation within your service not on a specific time of the day but every x amount of time.
The timer object doesn't seem to expose any property or method that will tell you how much time has ellapsed since it first started ticking, for that you can use properties and get the current time whenever SetTimer is called, set a property in the ASMSService1 class and get the difference with the current time when FirstSlotOperations is called.
Maybe this isn't exactly what you want to do but unless you get a little more specific about your expectations it's hard to address them efficiently.
You don't need any object to get current time. Just use:
private void FirstSlotOperations(object e)
{
DateTime current = DateTime.Now;
}
An object passed as an argument in callback function is timer object so you can't get data from it. You can use it only to operate on timer object for example.
private void FirstSlotOperations(object e)
{
Timer t = e as Timer;
t.Change(1000, 0);
}

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.

Getting notified when the datetime changes in c#

Recently I was trying to make a calendar application that will display the current year-month-date to the user. The problem is, if the user is gonna keep my application running even for the next day, how do I get notified ?? How shall I change the date displayed ? I don't wanna poll the current date to update it. Is this possible in c#.
Note: I tried out the SystemEvent.TimeChanged event, but it works only if the user manually changes the time / date from the control panel.
#OddThinking's answer will work (you could set a timer for the interval instead of sleeping). Another way would be to set a timer with a 1 minute interval and simply check if the system date has changed. Since you are only executing some lightweight code once a minute, I doubt the overhead would be noticable.
public void Main()
{
var T = new System.Timers.Timer();
T.Elapsed += CallBackFunction;
var D = (DateTime.Today.AddDays(1).Date - DateTime.Now);
T.Interval = D.TotalMilliseconds;
T.Start();
}
private void CallBackFunction(object sender, System.Timers.ElapsedEventArgs e)
{
(sender as System.Timers.Timer).Interval = (DateTime.Today.AddDays(1).Date - DateTime.Now).TotalMilliseconds;
}
Can you simply work out the number of seconds until midnight, and then sleep for that long?
Try looking into monitoring WMI events, you should be able to create a Wql event query that monitors the day of week change (i.e. ManagementEventWatcher etc) and then setup an event handler that fires when the event arrives.
using System;
using System.Management;
class Program
{
public static void Main()
{
WqlEventQuery q = new WqlEventQuery();
q.EventClassName = "__InstanceModificationEvent ";
q.Condition = #"TargetInstance ISA 'Win32_LocalTime' AND TargetInstance.Hour = 22 AND TargetInstance.Minute = 7 AND TargetInstance.Second = 59";
Console.WriteLine(q.QueryString);
using (ManagementEventWatcher w = new ManagementEventWatcher(q))
{
w.EventArrived += new EventArrivedEventHandler(TimeEventArrived);
w.Start();
Console.ReadLine(); // Block this thread for test purposes only....
w.Stop();
}
}
static void TimeEventArrived(object sender, EventArrivedEventArgs e)
{
Console.WriteLine("This is your wake-up call");
Console.WriteLine("{0}", new
DateTime((long)(ulong)e.NewEvent.Properties["TIME_CREATED"].Value));
}
}
How about a thread that checks for change in date. The thread can have some events that the controls that need this information can subscribe to.

Categories

Resources