System.Timers.Timer and Daylight Saving Time - c#

I have some timers that read HH:MM:SS from a table to figure out when to run on a daily basis.
For example:
Timer A needs to run every Monday at 13:00:00
Timer B needs to run every Tuesday at 02:00:00
Timer C needs to run every hour
So in my code I figure out what the current time is and then calculate the milliseconds from DateTime.Now() to the next occurrence of when the timer should run. When the timer's Elapsed event has completed, it recalculates when it is supposed to run next. This created a problem over this weekend due to the time change.
Is there a better way to do this? Would DateTime.UtcNow be a better alternative? Maybe convert the time string in the database to a UTC time and then figure out the difference between DateTime.UtcNow() instead of DateTime.Now()?

You can do several things to solve this problem.
One is to use UTC for all your scheduled jobs. That gives you a robust and predictable system without a lot of complications or testing burden. But the jobs that run at 03:00 on Mondays in the summer will run at 02:00 in the winter. If that's OK, the UTC strategy is a good one.
(Testing timezone switchover use cases is a pain, and if you use UTC for everything your test burden is reduced.)
Another is to get serious with your date arithmetic, and be very careful. C#'s DateTime class does a good job of date arithmetic even on changeover dates.
So, let's say you need to run a process once a week on Sunday at 01:30. That's in the nightmare hour in the USA ... it doesn't happen in the spring changeover, and it happens twice in the fall changeover. But you still want the process to run once.
What you do is this: Keep a "next scheduled time" value. Each time you finish running the job, compute the "next scheduled time" value for the next run. This might work like this:
var today = DateTime.Today.AddDays(7); /* midnight a week from now */
TimeSpan runTime = TimeSpan.Parse("01:30");
var nextRun = today + runTime;
Then, save that nextRun DateTime value. Later on you can figure out how long it is until the next run. This is a good way to do that. There are others.
var msUntilNextRun = (nextRun.Ticks - DateTime.Now.Ticks) / 10000;
If the msUntilNextRun value comes up reasonably small and positive, you can sleep until it's time for the run. If it comes up small and negative, you overslept--run immediately (oversleeping is very common).
Adding the days to the present midnight value, then adding the time to that, then figuring how long to wait, is a way to get a reasonable runtime even on changeover days.

Related

Compute difference of DateTimes from different time zones

There are 2 events (start and stop of some job) in the past which happened in different time zones.
I need to compute duration of the job.
I can get difference between those time zones in minutes and compute duration like this:
var duration = endTime - startTime.AddMinutes(diff);
However, there is a thing which confuses me.
Suppose start event happend in California and end event was in say Israel.
Right now difference between these time zones is 9 hours - California just switched to the day light and Israel not yet.
Next week this difference will be 10 hours because Israel will switch.
So, duration will be different if computed now and on the next week.
What is the right way to compute it?
Use DateTimeOffset?
So, duration will be different if computed now and on the next week.
I think you're forgetting that its you who is moving through time. not the project start and end times. therefore results will always be the same.
Id be tempted though just to convert the second time into the zone of the first, so it's just a straight diff. to convert from utc to any other zone you can use the following code
DateTime timeUtc = DateTime.UtcNow;
TimeZoneInfo cstZone = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
DateTime cstTime = TimeZoneInfo.ConvertTimeFromUtc(timeUtc, cstZone);
Theres also good info at https://learn.microsoft.com/en-us/dotnet/standard/datetime/converting-between-time-zones

could DateTime.Ticks value be repeated because culture hour changing

First of all, sorry about my ignorance and my awful english skills, i work to improve them.So here goes my question:
I want use DateTime.Ticks (instead Guid.NewGuid) in order to calculate an identifier and a question is being raised to me. In my current culture we have 2 days on the year when we change the official time: in octuber we add an hour and in april we remove it.
how does it affect to the ticks value? how ticks value is calulated? As far as i understand based on https://msdn.microsoft.com/en-us/library/system.datetime.ticks%28v=vs.110%29.aspx it seems it is not able to be a repeat value because based on the text (...)It does not include the number of ticks that are attributable to leap seconds(...) .
there could be repeated ticks?, (maybe other question would be how long a tick lasts, depends on the computer? )
If i'm not wrong it cant be repeated.
Moreover, Maybe there could be a lot of stuff i misunderstand so i'm really sorry again...
Even without DST changes, you can observe DateTime.Now.Ticks returning the same value multiple times, due to the granularity of the system clock.
But with DST changing, if you use DateTime.Now, you will indeed see the same values repeating for one hour per year. The Ticks property is just "the number of ticks since the DateTime epoch, in whatever kind of value is represented". (A DateTime value can be one of three "kinds" - universal, local, or unspecified. It's all a bit of a mess.)
If you use DateTime.UtcNow you shouldn't see that if your system clock only moves forward... but it's entirely possible for system clocks to be changed, either manually or in an automated way, to correct them for drift. Basically, it's not a good source of uniqueness on its own.
(In terms of the length of a tick - the tick in DateTime is always 100ns. That's not true for Stopwatch, where you need to use the Frequency property to find out how long a tick is, or use the Elapsed property to just find the elapsed time as a TimeSpan.)

Daylight Saving Time change schedule trigger for a marginal time

I'm coding a scheduling app and I'm curious how to handle the following marginal situation concerning the Daylight Saving Time (DST) change:
Say, we're in the time zone where the DST:
Starts on 2014-Mar-9 at 2:00:00 AM (clock is adjusted forward)
Ends on 2014-Nov-2 at 2:00:00 AM (clock is adjusted backward)
Suppose, an end-user scheduled my app for 2014-Nov-2, 2:00:00 AM.
Let's assume that the local date/time now is 2014-Nov-2, 1:59:99 AM.
When should my app fire the schedule -- in 1 second, or in 1 hour and 1 second?
Is there a standard that defines how to deal with this situation?
According to wikipedia the rules for daylight saving time are:
...in spring the clock jumps forward from the last moment of 01:59
standard time to 03:00 DST and that day has 23 hours, whereas in
autumn the clock jumps backward from the last moment of 01:59 DST to
01:00 standard time, repeating that hour, and that day has 25
hours.[37] A digital display of local time does not read 02:00 exactly
at the shift to summertime, but instead jumps from 01:59:59.9 forward
to 03:00:00.0.
So while the time and date is different around the world the rules are similar(ignoring Australia's Lord Howe Island which uses a half-hour shift). The hour that jumps backwards or forwards is not touched but the hour that is jumped to.
So in my opinion you should trigger the schedule in one hour and one second.
If you would trigger it in one second and the user wants to stop the schedule at 3 o'clock it would run for two hours instead of one which appears to be incorrect (2-3 = 1 hour).
I agree about all of the comments that "what you should do" is highly dependent on what your users expect, but I will give my opinion anyway.
If you are scheduling a single event, you should be able to test the date and time the user provided to see if it's either invalid (in the spring DST transition), or ambiguous (in the fall DST transition). In the invalid case, prompt something like "sorry, that time is invalid". In the ambiguous case, prompt something like "did you mean 1:30 PDT (UTC-7) or 1:30 PST (UTC-8)?" and handle the selection accordingly.
But I'll approach your question from the use case of a recurring event, such as a daily alarm clock that fires every day at the same time. What would I expect as the user of an alarm clock?
If I schedule a daily time at 2:00 AM, but in the spring transition the clock goes from 1:59:59 to 3:00:00, I'd expect the alarm to go off right at 3:00:00. I certainly wouldn't want it to go off at 4:00:00 - that would be an extra hour. I also wouldn't want the alarm to not fire at all just because 2:00 didn't technically occur.
If I schedule a daily time at 1:00 AM, but in the fall transition the clock goes from 1:59:59 back to 1:00:00 - as a user of this alarm, I would expect it to go off on the first occurrence (the daylight time) only. Occurring twice would just be annoying.
But here we see how this illustrates needing to know your users expectations. What if I could tell my alarm clock to let me have that extra hour back? "Please Mr. Alarm Clock, I'd like to use my extra DST hour to sleep in late. Wake me up at the second occurrence of 1:00." - Now I haven't personally seen any alarm clocks that work this way, but I think you get my point.
Now maybe you're not working with alarm clocks. Maybe this is a timed wire-transfer or some other time-sensitive item. You should work through the expected logic and see what makes sense for you.
Be aware that DST rules vary drastically by time zone. The world does not do DST all at the same time. Much of it doesn't do it at all.
For additional clarity on DST behavior, see the charts in the DST tag wiki.

.Net - Time of the day

I am working on an application that needs to set rules for periods of time. The company has different branches, each branch can set its own rules (i.e a branch starts work at 8.30 am, ends work at 17.30 pm, with 30 minutes pause for lunch; another branch start at 9.00, ends at 19.00 with 1 hour pause...)
So I need to define a class (let's call it WorkingDayDefinition for the moment) where start and end are not actually a DateTime, because they are not referred to any specific day in particular.
At the moment the only option I see in C# is using Timespan for setting a duration from the beginning of the day, so that 8.30 pm would be TimeSpan(8,30,0) to be added to the Day part of whichever day.
Is this a best practice in C#?
I searched for third parties libraries that could help me, but so far my best bet is this one:
http://www.codeproject.com/Articles/168662/Time-Period-Library-for-NET
that is not strictly what I need
You could use Noda Time. It provides a LocalTime (see here):
LocalTime is an immutable struct representing a time of day, with no reference to a particular calendar, time zone or date.
For 8.30 you would do something like:
LocalTime openingAt = new LocalTime(8, 30);
To me TimeSpam seems very suitable for what you want. It holds an interval of time, sometimes between two events, but in your case between the start of the day and the time you start/finish work. There is no reason I can think of not to use it just because the name might suggest this wasn't the original intention of the class. Plus it already integrates well with DateTimes for any time calculations you need to do later on down the road.

Does Daylightsaving time cause DateTime calculations to become negative

We are currently rewritting the core of our services, basically we have scheduled tasks that can run on intervals, dates, specific times etc etc etc.
Currently we're wondering if daylightsaving might cause trouble for us, basically we calculate the next possible runtime, based on what days the task should execute and between what times, and what interval. We do this by taking the current time, and adding days/minutes/hours to this DateTime.
We then take this new run time and subtract DateTime.Now from this DateTime, leaving us with the timespan untill the next run.
How ever, what if the current time is 01:50 on a daylightsavings day, we add 20 minutes, which is our set interval, and end up with a time of 02:10, how ever since this is daylightsavinds, it's actually 01:10.
When i subtract the current time (01:50) from the 01:10 (which is actually 02:10) does this return a negative value which i need to work around or does this never ever return a negative value because DateTime is just a long underneath holding the proper information?
Basically, the following code, is the check needed or not?
//Get interval between nextrun and right now!
double interval = (NextRun - DateTime.Now).TotalMilliseconds;
//Check if interval is ever less or equal to 0, should never happen but maybe with daylight saving time?
if(interval <= 0)
{
//Set default value
interval = IntervalInMilliseconds;
}
We believe that this check isn't needed but our googling so far hasn't given us a definative answer.
Use DateTime.UtcNow instead of DateTime.Now EVERYWHERE
First of all, you can try it yourself as it will help you understand how it works.
Essentially, using your example above, if you have 20 minutes to a local time, it would be 2:10 and not 1:10 as the computation is done in local time. If you want to get 1:10, you need to convert local time to universal time, add 20 minutes and then convert back to local time.
If you want real elapsed time, then you have to convert time to universal time before computing time difference. Also, if you work in local time, you won't be able to differentiate ambiguous time when the clock goes back.

Categories