Time check spanning 2 days - c#

I am creating a windows service, which checks folders, other services ect. and sends alert textmessages if any of these are down. However, I am not interested in getting alert messages during a given period of time (from 23.00 evening to 07.00 morning).
The service is set up through an XML configuration file, where this period of silence can be predefined.
I need a method to check if the service is operating in the period of time, so it will suspend text messaging. The service checks for this period every 5 minutes, so I cannot figure out how to cope shifting of days, during these checks.
To elaborate:
My current code:
bool silende = false;
DateTime silenceModeFrom = new DateTime(
DateTime.Now.Year,
DateTime.Now.Month,
DateTime.Now.Day,
int.Parse(doc.XPathSelectElement(
"//SurveilanceServiceConfig/SilenceModeTimeFrom").Value),
00,
00);
DateTime silenceModeTo = silenceModeFrom.AddHours(
int.Parse(doc.XPathSelectElement(
"//SurveilanceServiceConfig/SilenceModeTimeHours").Value));
if (DateTime.Now > silenceModeFrom && DateTime.Now < silenceModeTo)
{
silence = true;
}
In this code, the check works if it is made before 24.00, but not after as DateTime.Now.Day etc., will be the next day. So in theory, code only validates silence period as being from 23.00 to 24.00 per day.

You aren't that far off...
There is a slight issue with your code as it stands, everytime you call DateTime.Now the time would have changed - you need to capture that instance of time when the service is triggered i.e.
var instant = DateTime.Now;
DateTime silenceModeFrom = new DateTime(instant.Year, instant.Month, instant.Day, int.Parse(doc.XPathSelectElement("//SurveilanceServiceConfig/SilenceModeTimeFrom").Value), 00, 00);
DateTime silenceModeTo = silenceModeFrom.AddHours(int.Parse(doc.XPathSelectElement("//SurveilanceServiceConfig/SilenceModeTimeHours").Value));
bool silence = instant.TimeOfDay >= silenceModeFrom.TimeOfDay && instant <= silenceModeTo;
Looking at this code though, your time window appears wrong. You aren't really interested in the Date at all here - it's really just the time. Therefore, anything between 23:00hrs - 07:00hrs is considered the "silent" period i.e.
int curHour = DateTime.Now.Hour;
int silenceStartHour = int.Parse(doc.XPathSelectElement("//SurveilanceServiceConfig/SilenceModeTimeFrom").Value);
int silenceEndHour = int.Parse(doc.XPathSelectElement("//SurveilanceServiceConfig/SilenceModeTimeHours").Value);
bool silence = curHour > silenceStartHour || curHour < silenceEndHour;
The logic for determining whether you are in the silent period can be improved slightly to account for a range that is all in one day, or a range that is split over midnight.
bool silence = silenceStartHour <= silenceEndHour
? (curHour >= silenceStartHour && curHour < silenceEndHour)
: (curHour >= silenceStartHour || curHour < silenceEndHour);

Related

How do I know Daylight Saving Time just went off when it JUST went back an hour? [duplicate]

This question already has answers here:
Timer callback raised every 24 hours - is DST handled correctly?
(3 answers)
Closed 5 years ago.
I'm not in front of my code right now, but don't really think I need it to ask this question. So I have a countdown timer that goes off every 18 hours and then resets. The timer checks the current DateTime.Now and adjusts the countdown timer as needed. I am having an issue trying to account for when daylight savings when it goes back an hour because; for example this past event on November 5th 2017 at 2am it goes back to 1am but when I do DateTime.IsDaylightSavingTime() it tells me that it's false even though Daylight Saving Time just went off. This makes my timer go back an extra hour because it thinks that Daylight Saving Time still hasn't happen for that one hour period. How would I get around this?
If you realy need to use local time for some reason, than you should count for DST changes in advance (prior scheduling next event).
TimeZoneInfo.GetAdjustmentRules() should help you to get the time and delta of next DST adjustment.
Following is the code for getting upcomming adjustment:
public static DateTime? GetNextAdjustmentDate(TimeZoneInfo timeZoneInfo)
{
var adjustments = timeZoneInfo.GetAdjustmentRules();
if (adjustments.Length == 0)
{
return null;
}
int year = DateTime.UtcNow.Year;
TimeZoneInfo.AdjustmentRule adjustment = null;
foreach (TimeZoneInfo.AdjustmentRule adjustment1 in adjustments)
{
// Determine if this adjustment rule covers year desired
if (adjustment1.DateStart.Year <= year && adjustment1.DateEnd.Year >= year)
adjustment = adjustment1;
}
if (adjustment == null)
return null;
//TimeZoneInfo.TransitionTime startTransition, endTransition;
DateTime dstStart = GetCurrentYearAdjustmentDate(adjustment.DaylightTransitionStart);
DateTime dstEnd = GetCurrentYearAdjustmentDate(adjustment.DaylightTransitionEnd);
if (dstStart >= DateTime.UtcNow.Date)
return dstStart;
if (dstEnd >= DateTime.UtcNow.Date)
return dstEnd;
return null;
}
private static DateTime GetCurrentYearAdjustmentDate(TimeZoneInfo.TransitionTime transitionTime)
{
int year = DateTime.UtcNow.Year;
if (transitionTime.IsFixedDateRule)
return new DateTime(year, transitionTime.Month, transitionTime.Day);
else
{
// For non-fixed date rules, get local calendar
System.Globalization.Calendar cal = CultureInfo.CurrentCulture.Calendar;
// Get first day of week for transition
// For example, the 3rd week starts no earlier than the 15th of the month
int startOfWeek = transitionTime.Week * 7 - 6;
// What day of the week does the month start on?
int firstDayOfWeek = (int)cal.GetDayOfWeek(new DateTime(year, transitionTime.Month, 1));
// Determine how much start date has to be adjusted
int transitionDay;
int changeDayOfWeek = (int)transitionTime.DayOfWeek;
if (firstDayOfWeek <= changeDayOfWeek)
transitionDay = startOfWeek + (changeDayOfWeek - firstDayOfWeek);
else
transitionDay = startOfWeek + (7 - firstDayOfWeek + changeDayOfWeek);
// Adjust for months with no fifth week
if (transitionDay > cal.GetDaysInMonth(year, transitionTime.Month))
transitionDay -= 7;
return new DateTime(year, transitionTime.Month, transitionDay);
}
}
You'd need to add some more code to retrieve and apply the adjustment delta.
Well - now, when you see all the hard work that would need to be done (and than maintained and made sure to be bug free), you might want to rething your problem to be able to use UTC.
I would use DateTime.UtcNow you won't have the issue with daylight savings

How to handle daylight saving when using the Outlook C# GetFreeBusy() API?

I have an Outlook VSTO addin and I am doing search for resource calendar availability using the GetFreeBusy() API Calll which, given a date, will search over the next 28 days in 30 minute increments (by default) to determine which slots are free and which are busy. It works fine except I am struggling to figure out how to cope with the situation where a daylight savings time exists within that 28 day interval.
Here is my code:
using Microsoft.Office.Interop.Outlook;
string freeBusy = exchangeUser.GetFreeBusy(startDate, 30, true);
this gives me back a string like this that returns free / busy availability in 30 minute increments for 28 days.
0000000000000000202222222222000000000000000000000000000000000222222
this string is always 1344 characters long (48 slots per day * 28 days)
where each character represents a 30 minute slot and shows 0 if the time is free. I have the following parsing code that I took from this Microsoft article that returns an array of free time slots:
private IEnumerable<DateTime> ParseFreeBusy(string freeBusyString, DateTime startingDate)
{
var timeSlots = new List<DateTime>();
for (int i = 0; i < freeBusyString.Length; i++)
{
double slot = i * 30;
DateTime timeSlot = startingDate.Date.AddMinutes(slot);
bool isFree = freeBusy.Substring(i, 1) == "0";
if (isFree)
{
timeSlots.Add(timeSlot);
}
}
return timeSlots;
}
If I plug in October 25th as the start date when I look at the results every thing lines up perfectly up until November 2nd at 2AM (given daylight savings)
The root issue is that my naive code is simply increments and keeps adding 30 minutes for each entry since I am simply looping through each slot and doing this:
startingDate.Date.AddMinutes(slot);
I did a test and booked a calendar slot from 1AM - 2AM on November 2nd and this is what i get from GetFreeBusy() starting on that day
002222000...
so using the default loop above (remember, every character is a 30 min slot and 0 = free), this would translate to the following slot logic:
12L00 AM - free (0)
12:30 AM - free (0)
1L00 AM - booked (2)
1:30 AM - booked (2)
THESE NEXT TWO "booked" below is really representing the 2nd 1AM - 2AM since we roll the clocks back an hour
2:00 AM - booked (2)
2:30 AM - booked (2)
3:00 AM - free (0)
which is wrong as my code would show 2AM - 3AM booked when the "real" 2-3A AM is free. If my parsing was correct and handled this rollback, I would end up with this correct answer of:
12L00 AM - free (0)
12:30 AM - free (0)
1L00 AM - booked (2)
1:30 AM - booked (2)
IGNORE the second 1AM to 2AM as its already taken care of
2:00 AM - free (0)
2:30 AM - free (0)
3:00 AM - free (0)
What is interesting is that regardless of daylight savings, the resulting string is always 1344 characters long (I would have expected it to be shorter or longer on those months with daylight savings implications).
Does anyone have any experience with using outlook GetFreeBusy() and understand for how to deal with this situation when you hit a daily savings time slot?
I have been playing around with a few ideas like:
var tzInfo = TimeZoneInfo.Local;
if (tzInfo.IsAmbiguousTime(timeSlot))
{
//this would be a time to do something
}
or something like
DaylightTime daylightTime = tz.GetDaylightChanges(minStartTime.Year);
if (daylightTime.End == proposedTimeSlot)
{
daylightSavingsOffset = daylightSavingsOffset + ((daylightTime.Delta.Hours * 60) / meetingDuration);
}
but I am not completely sure what do with this once i detect the "special slots" and I can't find any documentation or recommendations around this situation.
Any suggestions?
What is interesting is that regardless of daylight savings, the resulting string is always 1344 characters long (I would have expected it to be shorter or longer on those months with daylight savings implications).
It's completely logical, Let's start with GetFreeBusy, It happens because the result is based on duration and specific intervals not Date and time stamps, and as we know Date and Time is relative to our location based on time zone but elapsed time and duration is not,let's assume we have meeting in 10 hours from now, we maybe are in different time Zones but after 10 hours (relative to our location) we both should meet each other, but our local times may vary significantly, the system works this way because it should be able to operate across different time zones at the same time, so it uses UniversalTime at the heart and converts it back to local time for generating the result.
Now let's check the code, when we use startingDate.Date.AddMinutes(slot); we are not considering DateTimeSaving as we are operating on our local time and the addition is relative to it, by using UniversalTime we can create a unified base point for our time additions and intervals, after that by converting it back to local time we can apply date time saving to it,
so I believe this code should work as expected:
private static IEnumerable<DateTime> ParseFreeBusy(string freeBusyString, DateTime startingDate)
{
var timeSlots = new HashSet<DateTime>();
var utc = startingDate.ToUniversalTime();
var timeZone = TimeZone.CurrentTimeZone; //can change to particular time zone, currently set to local timezone of the system
for (int i = 0; i < freeBusyString.Length; i++)
{
double slot = i * 30;
DateTime timeSlot = utc.AddMinutes(slot);
bool isFree = freeBusyString.Substring(i, 1) == "0";
if (isFree)
{
var localTimeSlot = timeZone.ToLocalTime(timeSlot);
timeSlots.Add(localTimeSlot);
}
}
return timeSlots;
}
NOTE:: beside using UTC for time, I changed the List to HashSet because if you have free slot on those specific times you would get duplicate entries, by using HashSet this problem won't occur.
here is a method I used for testing it:
private static void TestFreeSlots()
{
var saving = TimeZone.CurrentTimeZone.GetDaylightChanges(DateTime.Now.Year);
var datetime = new DateTime(saving.End.Year, saving.End.Month, saving.End.Day - 1);
//you may need to change the string to see effective result
var result = ParseFreeBusy("0000000000000000000000000000000000000000000000002222000", datetime);
}
and finally here is a little sample to demonstrate the method used here
private static void TestTimeZone()
{
var saving = TimeZone.CurrentTimeZone.GetDaylightChanges(DateTime.Now.Year);
var datetime = new DateTime(saving.End.Year, saving.End.Month, saving.End.Day - 1);
var utc = datetime.ToUniversalTime();
var timeZone = TimeZone.CurrentTimeZone;
for (var i = 0; i < 120; i++)
{
var next = timeZone.ToLocalTime(utc);
Console.WriteLine(next);
utc = utc.AddMinutes(30);
}
}
and your results should be similar to this:
This first function finds time slots that Outlook will return as duplicates due to DST. It can probably stand some refactoring but it's effective for now: (EDIT: I modified the function so it doesn't remove time slots as you go into DST).
public static Collection<DateTime> GetDuplicateSlots(
TimeZoneInfo timeZone, DateTime start, int intervalLength, int numOfIntervals)
{
Collection<DateTime> duplicates = new Collection<DateTime>();
bool dstAtStart = timeZone.IsDaylightSavingTime(start);
for (int interval = 0; interval < numOfIntervals; interval++)
{
DateTime current = start.Date.AddMinutes(interval * intervalLength);
if (dstAtStart && !timeZone.IsDaylightSavingTime(current))
{
duplicates.Add(current);
duplicates.Add(current.AddMinutes(intervalLength));
return duplicates;
}
}
return duplicates; // no duplicates
}
Then we just need to adjust for the duplicates when we go through the string of free/busy time slots:
public static void DisplayFreeBusy(
string freeBusyString, DateTime start, int intervalLength)
{
TimeZoneInfo cst = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
Collection<DateTime> duplicateSlots =
GetDuplicateSlots(cst, start, intervalLength, freeBusyString.Length);
int duplicatesConsumed = 0;
for (int slot = 0; slot < freeBusyString.Length; slot++)
{
int actualSlot = slot - duplicatesConsumed;
DateTime slotTime = start.Date.AddMinutes(actualSlot * intervalLength);
if (duplicatesConsumed != duplicateSlots.Count &&
duplicateSlots.Contains(slotTime))
{
duplicatesConsumed++;
}
else
{
Console.WriteLine("{0} -- {1}", slotTime, freeBusyString[slot]);
}
}
}
Note that the actualSlot variable corresponds to the time slots, while the slot variable still corresponds with a character in the free/busy string. When a duplicate is found, it is "consumed" and that character in the string is skipped. Once the duplicates have been consumed, the function will continue normally from that point.
I live in Arizona and we don't have DST so I had to force a different time zone. You can obviously substitute your local time zone instead of CST.
I tested this with a shorter input string but I added the extra '2' characters for the daylight savings slots. It handled the excess slots and prints out the proper number of slots.

Determine if current time between multiple time spans

I'm having trouble figuring out which tradings session any particular time is in.
There are four possible sessions, show in this picture taken from ForexFactory.com
I have this method that I need to check is currentTime is during the specified trading session.
public bool IsTradingSession(TradingSession tradingSession, DateTime currentTime)
{
//currentTime is in local time.
//Regular session is 5PM - next day 5PM, this is the session in the picture.
//Irregular sessions also occur for example late open (3AM - same day 5PM) or early close (5PM - next day 11AM)
DateTime sessionStart = Exchange.ToLocalTime(Exchange.CurrentSessionOpen);
DateTime sessionEnd = Exchange.ToLocalTime(Exchange.CurrentSessionClose);
if(tradingSession == TradingSession.Sydney)
return ....... ? true : false;
if(tradingSession == TradingSession.Tokyo)
return ....... ? true : false;
if(tradingSession == TradingSession.London)
return ....... ? true : false;
if (tradingSession == TradingSession.NewYork)
return ....... ? true : false;
return false;
}
Use:
bool isSydneySession = IsTradingSession(TradingSession.Sydney, CurrentTime);
bool isTokyoSession = IsTradingSession(TradingSession.Tokyo, CurrentTime);
bool isLondonSession = IsTradingSession(TradingSession.London, CurrentTime);
bool isNewYorkSession = IsTradingSession(TradingSession.NewYork, CurrentTime);
Thank you
I'd suggest writing a simple function for each trading session, which takes a DateTime and returns a bool indicating if it's open at that time.
var sydneyOpen = new TimeSpan(17, 0, 0);
var sydneyClose = new TimeSpan(2, 0, 0);
Func<DateTime, bool> isOpenInSydney = d =>
(d.TimeOfDay > sydneyOpen || d.TimeOfDay < sydneyClose);
// same for other markets, write a function to check against two times
Then place these into a Dictionary<TradingSession, Func> like this for generic retrieval...
var marketHours = new Dictionary<TradingSession, Func<DateTime, bool>>();
marketHours.Add(TradingSession.Sydney, isOpenInSydney);
// add other markets...
And then your existing method simply selects the appropriate function for the given TradingSession and applies it
public bool IsTradingSession(TradingSession tradingSession, DateTime currentTime)
{
var functionForSession = marketHours[tradingSession];
return functionForSession(currentTime);
}
I don't believe you need UTC time here as long as your application only runs in a single timezone, but daylight savings might cause problems.
A nice way to account for the problem of trading sessions which cover two days, as opposed to just one day, is to write a helper that precisely considers whether it's a 'cross-day' trading session and applies a different rule for you:
private bool IsBetween(DateTime now, TimeSpan open, TimeSpan close)
{
var nowTime = now.TimeOfDay;
return (open < close
// if open is before close, then now must be between them
? (nowTime > open && nowTime < close)
// otherwise now must be *either* after open or before close
: (nowTime > open || nowTime < close));
}
and then
var sydneyOpen = new TimeSpan(17, 0, 0);
var sydneyClose = new TimeSpan(2, 0, 0);
Func<DateTime, bool> isOpenInSydney = d => IsBetween(d, sydneyOpen, sydneyClose);
You can compare with > & < or compare ticks.
See related questions: Check if datetime instance falls in between other two datetime objects
To avoid the multiple if statements, you could also create a TradingSession object with start and end time and define a property/function to check if in session. When I have big switch or if blocks, it usually indicates a missed OO opportunity :)
TradingSession sydneySession = new TradingSession
{
StartTimeUtc = ...;
EndTimeUtc = ...;
}
The trading session object could then have a property IsInSession.
public bool IsInSession
{
get {
return DateTime.UTCNow >= StartTimeUtc && DateTime.UTCNow <= EndTimeUtc;
}
}
This uses UTC time to eliminate time zone issues.
You need to normalize your local times to UTC. You can then compare times across regions.
For each trading session, you need to know the session start and end time in UTC.
You need the current time in UTC. DateTime.UtcNow, for example.
You can then perform range comparisons for each trading session window:
if(tradingSession == TradingSession.Sydney)
return currentTimeUtc >= sydneyStartTimeUtc && currentTimeUtc <= sydneyEndTimeUtc;
etc...
If you're trying to validate that a transaction time is valid for a transaction on a particular trading session, this will work fine.
If however you're trying to figure out what trading session a trade belongs to based on its time, you will have multiple answers sometimes because the trading sessions overlap. Multiple trading sessions may be valid for a given time.

Determine if time falls in designated hour range

I am new at C#. I'd like to check whether a time is between 2 given hours, and if so then do something. Can anyone give me an example?
pseudocode example:
int starthour = 17;
int endhour = 2;
if ( hour between starthour and endhour){
dosomething();
}
How do I write a check on whether hour is between starthour and endhour? In C#, the time is returned in AM/PM format so I don't know if it will understand the 17 number as "5 PM".
Assuming you're talking about the current time, I'd do something like this:
// Only take the current time once; otherwise you could get into a mess if it
// changes day between samples.
DateTime now = DateTime.Now;
DateTime today = now.Date;
DateTime start = today.AddHours(startHour);
DateTime end = today.AddHours(endHour);
// Cope with a start hour later than an end hour - we just
// want to invert the normal result.
bool invertResult = end < start;
// Now check for the current time within the time period
bool inRange = (start <= now && now <= end) ^ invertResult;
if (inRange)
{
DoSomething();
}
Adjust the <= in the final condition to suit whether you want the boundaries to be inclusive/exclusive.
If you're talking about whether a time specified from elsewhere is within a certain boundary, just change "now" for the other time.
Actually, if we're dealing with pure hours here like a Abelian Ring from 0 to 23 and 0 again, I believe the following is actually a working solution:
(start <= end && start <= t && t <= end) or (start > end && (start <= t || t <= end))
Complex though this is, it is essentially an if-else where you have a different algorithm depending on whether start <= end or not, where t is the time you wish to test. In the first case, start and end are normal order, so t must be both greater than start and less than end. In the case where start is greater than end, the times outside the opposite range are what we want:
NOT(end < t and t < start)
Using DeMorgan's theorem:
NOT(end < t) or NOT(t < start)
NOT(t < start) or NOT(end < t)
t >= start or end >= t
start <= t or t <= end
This should solve your and my problems.
#JonSkeet
The thing is, looking at your algorithm, let's assume for a moment the time is 1am, day 1.
Now holds 1am Day 1
Today holds midnight Day 1
Start holds 5pm Day 1 (given the original example)
End holds 2am Day 1 (again from the example)
End holds 2am Day 2 (since start > end)
Now, unless I'm mistaken, start ≰ now since start is 5pm Day 1 and now is 1am Day 1 which is before now, therefore the test fails but the original question wanted 1am included in the range since 1am is between 5pm and 2am. Did I miss something?
#Brian
Also, looking at your code, I think you can detect 1am but now you would have a problem with 10pm (22:00) since your times become:
Start is 17
End is 26
Now is 22 + 24 = 46! so you will fail in the less-than test.
Clearly, the general case is very tricky! More so when you're restricted to Google Spreadsheets as I am.
When subtracting DateTimes, you get a TimeSpan struct that you can query for things like the total number of hours (the TotalHours property):
TimeSpan ts = starttime - endtime;
if(ts.TotalHours > 2)
{
dosomething();
}
If you want to see if the times are identical, then you can use TotalMilliseconds - for identical DateTimes, this will be equal to 0.
If you want to compare minutes also like I do you can use this snippet of code in java.
//Initialize now, sleepStart, and sleepEnd Calendars
Calendar now = Calendar.getInstance();
Calendar sleepStart = Calendar.getInstance();
Calendar sleepEnd = Calendar.getInstance();
//Assign start and end calendars to user specified star and end times
long startSleep = settings.getLong("startTime", 0);
long endSleep = settings.getLong("endTime", 0);
sleepStart.setTimeInMillis(startSleep);
sleepEnd.setTimeInMillis(endSleep);
//Extract hours and minutes from times
int endHour = sleepEnd.get(Calendar.HOUR_OF_DAY);
int startHour = sleepStart.get(Calendar.HOUR_OF_DAY);
int nowHour = now.get(Calendar.HOUR_OF_DAY);
int endMinute = sleepEnd.get(Calendar.MINUTE);
int startMinute = sleepStart.get(Calendar.MINUTE);
int nowMinute = now.get(Calendar.MINUTE);
//get our times in all minutes
int endTime = (endHour * 60) + endMinute;
int startTime = (startHour * 60) + startMinute;
int nowTime = (nowHour * 60) + nowMinute;
/*****************What makes this 100% effective***************************/
//Test if end endtime is the next day
if(endTime < startTime){
if(nowTime > 0 && nowTime < endTime)
nowTime += 1440;
endTime += 1440;
}
/**************************************************************************/
//nowTime in range?
boolean inRange = (startTime <= nowTime && nowTime <= endTime);
//in range so calculate time from now until end
if(inRange){
int timeDifference = (endTime - nowTime);
now.setTimeInMillis(0);
now.add(Calendar.MINUTE, timeDifference);
sleepInterval = now.getTimeInMillis() / 1000;
editor.putBoolean("isSleeping", true);
editor.commit();
Log.i(TAG, "Sleep Mode Detected");
returned = true;
}
bool CheckHour(DateTime check, DateTime start, DateTime end)
{
if (check.TimeOfDay < start.TimeOfDay)
return false;
else if (check.TimeOfDay > end.TimeOfDay)
return false;
else
return true;
}
int starthour = 17;
int endhour = 2;
int nowhour = DateTime.Now.Hour;
if (endhour < starthour)
{
endhour+=24;
nowhour+=24;
}
if (starthour <= nowhour && nowhour <= endhour)
{
dosomething();
}
I'm not sure which I prefer between this code and Jon Skeet's code.
Using Jon Skeet's solution above I added a fix where if start time is after beginning time eg You start the job after 6pm at night and end it the next morning at 5am. then you need to check this and apply another day to the end time. Hope it helps, I personally have spent too much time on this piece of work. have a great day :)
if (stopHour < startHour)
{
end = today.AddHours(stopHour+24);
}
Full Code is below.
private static bool IsInRunHours()
{
try
{
ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None).Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("appSettings");
// after = 18 before = 5
// Only take the current time once; otherwise you could get into a mess if it
// changes day between samples.
DateTime now = DateTime.Now;
DateTime today = now.Date;
Int32 startHour = ConfigurationManager.AppSettings["UpdateRunAfter"].ToInt();
Int32 stopHour = ConfigurationManager.AppSettings["UpdateRunBefore"].ToInt();
DateTime start = today.AddHours(startHour);
DateTime end = today.AddHours(stopHour);
if (stopHour < startHour)
{
end = today.AddHours(stopHour+24);
}
//ConfigurationManager.AppSettings["UpdateRunBefore"].ToInt()
//ConfigurationManager.AppSettings["UpdateRunAfter"].ToInt()
// Cope with a start hour later than an end hour - we just
// want to invert the normal result.
bool invertResult = end < start;
// Now check for the current time within the time period
bool inRange = (start <= now && now <= end) ^ invertResult;
if (inRange)
{
return true;
}
else
{
return false;
}
}
catch
{
return false;
}
}

Algorithm to check whether a certain hour falls into a given time period

Assume I've got a start and stop hour in which some processing should take place:
Start 20:00
End 07:00
Now what is the best algorithm to check if a certain DateTime hour value falls within this range? Thanks in advance!
Please note that the start and end times mentioned above indicate that we are dealing with an "overnight-job". Meaning that the period to be checked starts at 20:00 in the evening and ends at 07:00 on the following morning.
Assume you only have the time and not the date.
if end_time >= start_time:
return start_time <= current_time <= end_time
else:
return start_time <= current_time or current_time <= end_time
If you are sure it is in the same day
you also do not seem to care for seconds
Transform everything in minutes
startminute = 20 * 60 + 0
endminute = 7 * 60 + 0
eventminute = x * 60 + y // with event having the form xx:yy
return startminute < eventminute && eventminute < endminute
Another option would be to get the 3 times in DateTime format
DateTime start, end, event
return (start < event && event < end);
Assuming you have a start, end and now DateTime, you could use
bool within = start.TimeOfDay.TotalHours <= now.TimeOfDay.TotalHours &&
now.TimeOfDay.TotalHours <= end.TimeOfDay.TotalHours;
Without knowing how to do it in C#, I'd go with converting start and end time to a timestamp and then do a simple if (end time >= given time AND start time <= given time) comparison. Maybe that'll get you started or give you a hint what to search for.
I think c# supports greater than/less than operators for DateTime variables, so just say
if ((beginDateTime<myDateTime)&&(myDateTime<endDateTime))
{
...
}
Also greater than or equal to and less than or equal to are supported.
With an overnight window, I don't think there's anything particularly clever to be done except to directly check your DateTime's TimeOfDay against the boundaries:
using System;
namespace Question2355777
{
class Program
{
private static bool IsInOvernightWindow(
DateTime dateTimeUnderTest,
TimeSpan morningEnd,
TimeSpan eveningStart)
{
TimeSpan timeOfDay = dateTimeUnderTest.TimeOfDay;
return timeOfDay <= morningEnd || timeOfDay >= eveningStart;
}
static void Main(string[] args)
{
TimeSpan eveningStart = TimeSpan.FromHours(20);
TimeSpan morningEnd = TimeSpan.FromHours(7);
Console.WriteLine("{0} {1}",
DateTime.Today.AddHours(3),
IsInOvernightWindow(
DateTime.Today.AddHours(3),
morningEnd,
eveningStart));
Console.WriteLine("{0} {1}",
DateTime.Today.AddHours(12),
IsInOvernightWindow(
DateTime.Today.AddHours(12),
morningEnd,
eveningStart));
Console.WriteLine("{0} {1}",
DateTime.Today.AddHours(21),
IsInOvernightWindow(
DateTime.Today.AddHours(21),
morningEnd,
eveningStart));
Console.ReadLine();
}
}
}
produces
01/03/2010 03:00:00 True
01/03/2010 12:00:00 False
01/03/2010 21:00:00 True
// initializing with some sample values
TimeSpan start = TimeSpan.FromHours(20);
TimeSpan end = TimeSpan.FromHours(7);
DateTime now = DateTime.Now.TimeOfDay;
return start<end
? start <= now.TotalHours && now.TotalHours <= end
: start <= now.TotalHours || now.TotalHours <= end;
Use the TimeOfDay method:
DateTime dtStart = new DateTime(0,0,0,20,0,0);
DateTime dtEnd = new DateTime(0,0,0,7,0,0);
if (DateTime.Now.TimeOfDay < dtEnd.TimeOfDay || DateTime.Now.TimeOfDay > dtStart.TimeOfDay)
{
// your code here
}
Count all the times in units of minutes beginning from the start day.
struct DateTime {
uint_8 hour_;
uint_8 minute_;
};
bool
isTimeWithin( DateTime start, DataTime stop, DateTime query ) {
// The following times are counted from the beginning of start day
uint_16 startInMins = (60 * start.hour_ + start.minute_);
// Added 24*60 since "stop" is always "overnight" from "start"
uint_16 stopInMins = 24 * 60 + (60 * stop.hour_ + stop.minute_);
// The ternary operator checks whether "query" is in the same day as
// "start" or the next day
uint_16 queryInMins = (query.hour_ < start.hour_ ? 24 * 60 : 0 ) +
(60 * query.hour_ + query.minute_);
return ((startInMins <= queryInMins) && (queryInMins <= stopInMins));
}
EDIT: Improved Formatting.
if ALL you have are those values for start and stop, don't you have an empty set?
Ignore the obvious assumption - start day X, end day X + Y.
[edit]
since the question has been edited, so shall be the answer....
for start time, end time and 'test' time get the number of milliseconds from the epoch (define that any way you would like)
and then check to see if test is >= start and <= end
[/edit]

Categories