How can I check if current day is working day - c#

I have application that needs to be run on working days, and within working hours.
In application configuration, I've set start time in format
Monday-Friday
9:00AM-5:30PM
Now, I have a problem how to check if current day is within day boundare is (for the time is easy - parse time with DateTime.ParseExact and simple branch will do), but I don't know how to parse days.
I've tried with:
DayOfWeek day = DateTime.Now.DayOfWeek;
if (day >= (DayOfWeek)Enum.Parse(typeof(DayOfWeek), sr.start_day) &&
day <= (DayOfWeek)Enum.Parse(typeof(DayOfWeek), sr.end_day))
{ /* OK */ }
sr.start_day and sr.end_day are strings
but the problem occurred during weekend testing - apparently, in DayOfWeek enum, Sunday is first day of the week (refering to the comments on MSDN page
I suppose I could do some gymnastics with current code, but I am looking for the most readable code available.
Edit
Sorry for the misunderstanding - working days are not from Monday to Friday - they are defined as strings in config file, and they can be even from Friday to Saturday - which breaks my original code.

if ((day >= DayOfWeek.Monday) && (day <= DayOfWeek.Friday))
{
// action
}

From Hans Passant's comment on my original question:
Just add 7 to the end day if it is less than the start day. Similarly,
add 7 to day if it is less than the start day.
DayOfWeek day = DateTime.Now.DayOfWeek;
DayOfWeek start_day = (DayOfWeek)Enum.Parse(typeof(DayOfWeek), sr.start_day);
DayOfWeek end_day = (DayOfWeek)Enum.Parse(typeof(DayOfWeek), sr.end_day);
if (end_day < start_day)
end_day += 7;
if (day < start_day)
day += 7;
if (day >= start_day && day <= end_day)
{
//Action
}

extention for DateTime
public static bool IsWeekend(this DateTime date)
{
return new[] {DayOfWeek.Sunday, DayOfWeek.Saturday}.Contains(date.DayOfWeek);
}

This is an elegant solution for the problem. It's a class that can easily be imported into other projects. The coding allows the programmer to dynamically assign what days to check for and pass them as a string array to the class. The data can come from a database or be hard coded when you pass it to an instance of this class for processing. It returns the values of True if you're off work and False if you're working that day. Below the class I provided a simple example of implementation. This class features: Dynamic allocation of what days you have off, Simple error handler by setting strings to lowercase before comparing them, Easily integrated with a database that has your work schedule where your days off may not always be the same. Easily integrated as a hard coded number of days off.
// The Class To Check If You're Off Work
class DayOffChecker
{
public bool CheckDays(List<string> DaysOff)
{
string CurrentDay = DateTime.Now.DayOfWeek.ToString();
CurrentDay.ToLower();
foreach (string DayCheck in DaysOff)
{
DayCheck.ToLower();
if (CurrentDay == DayCheck)
{
return (true);
}
}
return (false);
}
}
// Example usage code:
class Program
{
List<string> DaysOff = List<string>();
DaysOff.Add("Saturday"); // Add some values to our list.
DaysOff.Add("Sunday");
DayOffChecker CheckToday = new DayOffChecker();
if(CheckToday.CheckDays(DaysOff))
{
Console.WriteLine("You're Off Today!!!");
}
}

We can also follow similar approach of checking if a given hour is between two hours. Following is the algorithm
checkIfFallsInRange(index,start,end)
bool normalPattern = start <= end ;
if ( normalPattern)
return index>=start && index<=end;
else
return index>=start || index <=end;

My simple solution to determining if the current day is a workday or not is:
public static bool IsWorkDay(this DateTime dt)
{
return IsWorkDay(dt, DayOfWeek.Sunday, DayOfWeek.Saturday);
}
public static bool IsWorkDay(this DateTime dt, params DayOfWeek[] noneWorkDays)
{
return !noneWorkDays.Contains(dt.DayOfWeek);
}
It assumes Sunday / Saturday are non-work days. Otherwise the user can specify the non-work days. And is an extension for easy of use.
Note: To avoid a loop could created a bit flag.

DayOfWeek Day = DateTime.Today.DayOfWeek;
int Time = DateTime.Now.Hour;
if (Day != DayOfWeek.Saturday && Day != DayOfWeek.Sunday)
{
if (Time >= 8 && Time <= 16)
{
//It is Weekdays work hours from 8 AM to 4 PM
{
}
else
{
// It is Weekend
}

You can use the DayOfWeek enumeration in order to see if a date is Sunday or Saturday. http://msdn.microsoft.com/en-us/library/system.dayofweek.aspx I hope this can help.

The line below will return "Sunday"
string nameOfTheDay = DateTime.Now.ToString("dddd", new System.Globalization.CultureInfo("en-GB")).ToLower();
if(nameOfTheDay != "sunday" && nameOfTheDay != "saturday")
{
//Do Stuff
}

public bool IsWeekend(DateTime dateToCheck)
{
DayOfWeek day = (DayOfWeek) dateToCheck.Day;
return ((day == DayOfWeek.Saturday) || (day == DayOfWeek.Sunday));
}

Related

Parsing leap year day without year always fails in C#

I'm trying to parse birthdays in the format of d/M without any year specified.
Using DateTime.TryParseExact(birthday, "d/M", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime birthdayDate) works most of the time, except when the birthday is at leap year day (aka 29/2), and the parsing never succeeds because it is default to current year. Using DatTimeStyles.NoCurrentDateDefault does not work either since it defaults to year = 1, which is not a leap year.
How do I do the parsing so it does not involve a hack (I don't want to parse it manually or manually add an arbitrary year to parse it as a full date either, they are all ugly and potentially fragile) and still work across all possible dates, including leap day? Existing questions does not help at all since nobody bothers to check if they work for leap day at all. I tried all of them and none of them worked.
A day and a month does not make a date - therefore they can't be parsed as a DateTime value without assuming a year. The .NET Framework assumes a year that is either the current year or year 1 - exactly because 2/29 is valid only on leap years - and this is a very reasonable assumption.
The .Net framework does not provide a built in way to store Day/Month values, but Noda Time does - Take a look at AnnualDate - It stores a day and a month but no year.
However, it doesn't have Parse or TryParse methods - so for that you still need to manually manipulate the input string and add a year (that is a leap year like 2016) in order to use the DateTime's TryParseExact method.
Update
As Matt Johnson wrote in his comment, Noda Time does provide a way for parsing text as an AnnualDate, using the AnnualDatePattern class.
The documentation has a page called Patterns for AnnualDate values that lists the supported patterns.
This question lacks the appropriate details, however
If you just want to parse a birth date and month including leap year dates, then just added a leap year to the end of the date.
I am not sure what you expect to do here, however you could try this
birthday = $"{birthday}/2016"; // leap year
DateTime.TryParseExact(birthday, "d/M/yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime birthdayDate);
Update
my question is how to not make TryParseExact assume the year
automatically by manually overriding it in some way
To be technical here, no you have to specify the leap year in the string if you are parsing a leap year month and day exclusively as in your example
There is a lot of checks and balances the TryParseExact method does, however here are the important bits.
In short, it uses the current year or year 1, and there is no way to tell it to choose a leap year specifically
private static bool CheckDefaultDateTime(ref DateTimeResult result, ref Calendar cal, DateTimeStyles styles)
{
if ((result.flags & ParseFlags.CaptureOffset) != (ParseFlags) 0 && (result.Month != -1 || result.Day != -1) && ((result.Year == -1 || (result.flags & ParseFlags.YearDefault) != (ParseFlags) 0) && (result.flags & ParseFlags.TimeZoneUsed) != (ParseFlags) 0))
{
result.SetFailure(ParseFailureKind.Format, "Format_MissingIncompleteDate", (object) null);
return false;
}
if (result.Year == -1 || result.Month == -1 || result.Day == -1)
{
DateTime dateTimeNow = DateTimeParse.GetDateTimeNow(ref result, ref styles);
if (result.Month == -1 && result.Day == -1)
{
if (result.Year == -1)
{
if ((styles & DateTimeStyles.NoCurrentDateDefault) != DateTimeStyles.None)
{
cal = GregorianCalendar.GetDefaultInstance();
result.Year = result.Month = result.Day = 1;
}
else
{
result.Year = cal.GetYear(dateTimeNow);
result.Month = cal.GetMonth(dateTimeNow);
result.Day = cal.GetDayOfMonth(dateTimeNow);
}
}
else
{
result.Month = 1;
result.Day = 1;
}
}
else
{
if (result.Year == -1)
result.Year = cal.GetYear(dateTimeNow);
if (result.Month == -1)
result.Month = 1;
if (result.Day == -1)
result.Day = 1;
}
}
if (result.Hour == -1)
result.Hour = 0;
if (result.Minute == -1)
result.Minute = 0;
if (result.Second == -1)
result.Second = 0;
if (result.era == -1)
result.era = 0;
return true;
}

C# - Validate an int-based DateTime without exceptions?

This question talks about validating a string representing a date, and in it folks mention that it's good to avoid using Exceptions for regular flow logic. And TryParse() is great for that. But TryParse() takes a string, and in in my case i've already got the year month and day as integers. I want to validate the month/day/year combination. For example February 30th.
It's pretty easy to just put a try/catch around new DateTime(int, int, int), but I'm wondering if there's a way to do it without relying on exceptions.
I'd also feel silly composing these ints into a string and then using TryParse().
The following will check for valid year/month/day combinations in the range supported by DateTime, using a proleptic Gregorian calendar:
public bool IsValidDate(int year, int month, int day)
{
return year >= 1 && year <= 9999
&& month >= 1 && month <= 12
&& day >= 1 && day <= DateTime.DaysInMonth(year, month);
}
If you need to work with other calendar systems, then expand it as follows:
public bool IsValidDate(int year, int month, int day, Calendar cal)
{
return year >= cal.GetYear(cal.MinSupportedDateTime)
&& year <= cal.GetYear(cal.MaxSupportedDateTime)
&& month >= 1 && month <= cal.GetMonthsInYear(year)
&& day >= 1 && day <= cal.GetDaysInMonth(year, month);
}
Use String Interpolation
int year = 2017;
int month = 2;
int day = 28;
DateTime dt;
DateTime.TryParse($"{month}/{day}/{year}", out dt);
As far as I know, there's no easy way to check for a DateTime's int's validity besides concatenating the ints into a correctly formatted string beforehand.
To avoid try/catch-ing, I would write a static utility class which utilizes DateTime.TryParse:
using System;
public static class DateTimeUtilities
{
public static bool TryParse(int year, int month, int day, out DateTime result)
{
return DateTime.TryParse(
string.Format("{0}/{1}/{2}", year, month, day), out result);
}
}
Usage:
DateTime dateTime;
if (DateTimeUtilities.TryParse(2017, 2, 30, out dateTime))
{
// success
}
else
{
// fail, dateTime = DateTime.MinValue
}
Pending the needs of your application, e.g. culture (thanks #Matt Johnson), I would also look into DateTime.TryParseExact.
Look at it this way. Any code that you write:
Will have to check month ranges 1-12
Will have to check day ranges by month, which means you'll have to hard code an array
Will have to account for leap years, which can be a pain the the rear
Rather than doing ALL that, and reinventing the wheel, and potentially getting it wrong -- why don't you keep it simple and just wrap the DateTime constructor in a try-catch and keep it moving? Let the nerds up in Redmond do all the hard work for this common task. The best solution is one that any developer following you can understand and rely upon quickly.
I'd bet money that under the hood, TryParse and the DateTime constructor are using the exact same validators, except that the latter throws an exception while the former does not. TryParse, for this, is overkill with all the extra string manipulation involved.

Get Dates based on Current Date and List of Week Days

I have something odd requirement. I have Current Date and List of Week Days. And I want next all possible date till the target date.
For i.e. Today, its 22-04-2014 And Tuesday. Target date is 15-05-2014I have 2 week days, Monday and Thursday. So code should find near by Week Day, which will be Thursday here. So It should return date of Thursday which is 24-04-2014. Now, next turn is of Monday which comes from List. So now, It should return date of Monday which is 28-04-2014.
It should keep repeating till the target date.
So, final result will be
24-04-2014,
28-04-2014,
1-05-2014,
5-05-2014,
8-05-2014,
12-05-2014
Please help me to get this type of result. Here, Monday and Thursday is not fixed. It can be any Day and any number of Day.
Update : Link to the working example - Example
You can try this code, i have tested it and working correctly
private List<DateTime> ProcessDate(DateTime dtStartDate, DateTime targetDate)
{
DateTime dtLoop = dtStartDate;
//dtRequiredDates to hold required dates
List<DateTime> dtRequiredDates = new List<DateTime>();
for (int i = dtStartDate.DayOfYear; i < targetDate.DayOfYear; i++)
{
if (dtLoop.DayOfWeek == DayOfWeek.Monday || dtLoop.DayOfWeek == DayOfWeek.Thursday)
{
dtRequiredDates.Add(dtLoop);
}
dtLoop = dtLoop.AddDays(1);
}
return dtRequiredDates;
}
You may have to enhance this codes so that it doesn't throw any exception based on the requirement.
UPDATE 2:
You can have another method which will accept the days of week as follows
private List<DateTime> ProcessDate(DateTime dtStartDate, DateTime targetDate, List<DayOfWeek> daysOfWeek)
{
DateTime dtLoop = dtStartDate;
List<DateTime> dtRequiredDates = new List<DateTime>();
for (int i = dtStartDate.DayOfYear; i < targetDate.DayOfYear; i++)
{
foreach (DayOfWeek day in daysOfWeek)
{
if (dtLoop.DayOfWeek == day)
{
dtRequiredDates.Add(dtLoop);
}
}
dtLoop = dtLoop.AddDays(1);
}
return dtRequiredDates;
}
Here is the Example
Hence you can pass any number of week days as you wish.
Hope this helps
You could try something like this:
List<DayOfWeek> listOfDays = new List<DayOfWeek>{DayOfWeek.Monday, DayOfWeek.Thursday};
var end = new DateTime(2014,05,15);
var day = DateTime.Now.Date;
while (day < end)
{
day.AddDays(1); // adds +1 days to "day"
if (listOfDays.Contains(day.DayOfWeek)) Console.WriteLine(day.Date.ToString());
}
(I can't test the code right now, so maybe you need to modify a little ;-)

Check if datetime instance falls in between other two datetime objects

I would like to know a simple algorithm to check if the given instance of datetime lies between another two instances in C#.
Note:
I skimmed though this How do I check if a given datetime object is "between" two datetimes? and it was for python and many more for php. Most of the other questions were regarding difference between the two.
Details:
I am more specific about the time, date does not matter to me. For example i got DataBase entry for a staff who works between 10:00 Am - 9:00 Pm and I would like to know which staff is engaged in class at the given time like 2:00 Pm. Now this would return me the staff's details who are engaged at this time.
Edit
After accepting the answer(been more than year back), i realized i had incorrectly described the problem. But all i think that was to be done back then was to do date and time comparison. So answers by both Jason and VikciaR work.
DateTime.Ticks will account for the time. Use .Ticks on the DateTime to convert your dates into longs. Then just use a simple if stmt to see if your target date falls between.
// Assuming you know d2 > d1
if (targetDt.Ticks > d1.Ticks && targetDt.Ticks < d2.Ticks)
{
// targetDt is in between d1 and d2
}
Do simple compare > and <.
if (dateB < dateA && dateA < dateC)
//do something
If you care only on time:
if (dateA.TimeOfDay>dateB.TimeOfDay && dateA.TimeOfDay<dateC.TimeOfDay)
//do something
Write yourself a Helper function:
public static bool IsBewteenTwoDates(this DateTime dt, DateTime start, DateTime end)
{
return dt >= start && dt <= end;
}
Then call:
.IsBewteenTwoDates(DateTime.Today ,new DateTime(,,));
You can, use:
if (date >= startDate && date<= EndDate) { return true; }
You can use:
if ((DateTime.Compare(dateToCompare, dateIn) == 1) && (DateTime.Compare(dateToCompare, dateOut) == 1)
{
//do code here
}
or
if ((dateToCompare.CompareTo(dateIn) == 1) && (dateToCompare.CompareTo(dateOut) == 1))
{
//do code here
}

Regular DateTime question

I'm writing a service but I want to have config settings to make sure that the service does not run within a certain time window on one day of the week. eg Mondays between 17:00 and 19:00.
Is it possible to create a datetime that represents any monday so I can have one App config key for DontProcessStartTime and one for DontProcessEndTime with a values like "Monday 17:00" and "Monday 19:00"?
Otherwise I assume I'll have to have separate keys for the day and time for start and end of the time window.
Any thoughts?
thanks
You could use a utility that will parse your weekday text into a System.DayOfWeek enumeration, example here. You can then use the Enum in a comparison against the DateTime.Now.DayOfWeek
You can save the day of the week and start hour and endhour in your config file, and then use a function similar to the following:
public bool ShouldRun(DateTime dateToCheck)
{
//These should be read from your config file:
var day = DayOfWeek.Monday;
var start = 17;
var end = 19;
return !dateToCheck.DayOfWeek == day &&
!(dateToCheck.Hour >= start && dateToCheck.Hour < end);
}
You can use DayOfTheWeek property of the DateTime.
And to check proper time you can use DateTime.Today (returns date-time set to today with time set to 00:00:00) and add to it necessary amount of hours and minutes.
The DateTime object cannot handle a value that means all mondays. It would have to be a specific Monday. There is a DayOfWeek enumeration. Another object that may help you is a TimeSpan object. You could use the DayOfWeek combined with TimeSpan to tell you when to start, then use another TimeSpan to tell you how long
This is very rough code, but illustrates that you can check a DateTime object containing the current time as you wish to do:
protected bool IsOkToRunNow()
{
bool result = false;
DateTime currentTime = DateTime.Now;
if (currentTime.DayOfWeek != DayOfWeek.Monday && (currentTime.Hour <= 17 || currentTime.Hour >= 19))
{
result = true;
}
return result;
}

Categories