Reputation: 249
I realize that similar questions to this have been asked, but I feel this questions has different requirements.
I need to check whether the current day is the Nth or Nth from last business day of the month. If it is, I kick off another task, else I exit.
Something like :
void doTask()
{
if (NthFirstOrNthLastBusinessDay())
{ // do stuff }
else
{ // do nothing }
}
bool NthFirstOrNthLastBusinessDay()
{}
So far, I think I could follow the answers here to get the last business day of the month (and similarly the first business day of the month), then apply a bunch of conditions to calculate the Nth business day from that date.
Is there a better way?
For example, if N is 4, my task should only run if today is the 4th business day of the month or the 4th from last business day of the month.
Essentially, I call this method everyday, it checks whether the current day satisfies this condition, and if so it runs the task, otherwise it doesn't.
So, my task should run on 28th July, 2014 and 6th August, 2014 and then 26th August, 2014 and so on.
EDIT : Here is some code I wrote in case N=4 :
/// <summary>
/// Checks if the current day is the 4th business day or the 4th last business day of the month
/// </summary>
/// <returns> True if current day satisfies condition, false otherwise </returns>
private bool NthFirstOrNthLastBusinessDay()
{
return (IsFourthBusinessDay() || IsFourthFromLastBusinessDay());
}
/// <summary>
/// Checks if today is the fourth business day of the month
/// </summary>
/// <returns> True if today satisfies condition, else false </returns>
private bool IsFourthBusinessDay()
{
var dateToday = DateTime.Today;
var firstDayOfThisMonth = new DateTime(dateToday.Year, dateToday.Month, 1);
switch (firstDayOfThisMonth.DayOfWeek)
{
case DayOfWeek.Sunday:
firstDayOfThisMonth = firstDayOfThisMonth.AddDays(4);
break;
case DayOfWeek.Monday:
firstDayOfThisMonth = firstDayOfThisMonth.AddDays(3);
break;
case DayOfWeek.Tuesday:
firstDayOfThisMonth = firstDayOfThisMonth.AddDays(3);
break;
default:
firstDayOfThisMonth = firstDayOfThisMonth.AddDays(5);
break;
} // firstDayOfMonth now contains first business day of month
return dateToday == firstDayOfThisMonth;
}
/// <summary>
/// Checks if today is the fourth from last business day of the month
/// </summary>
/// <returns> True if today satisfies condition, else false </returns>
private bool IsFourthFromLastBusinessDay()
{
var dateToday = DateTime.Today;
var lastDayOfThisMonth = new DateTime(dateToday.Year, dateToday.Month, DateTime.DaysInMonth(dateToday.Year, dateToday.Month));
switch (lastDayOfThisMonth.DayOfWeek)
{
case DayOfWeek.Saturday:
lastDayOfThisMonth = lastDayOfThisMonth.AddDays(-4);
break;
case DayOfWeek.Friday:
lastDayOfThisMonth = lastDayOfThisMonth.AddDays(-3);
break;
case DayOfWeek.Thursday:
lastDayOfThisMonth = lastDayOfThisMonth.AddDays(-3);
break;
default:
lastDayOfThisMonth = lastDayOfThisMonth.AddDays(-5);
break;
} // firstDayOfMonth now contains first business day of month
return dateToday == lastDayOfThisMonth;
}
Now I need to tweak the values for general N. Is there a better way?
Upvotes: 2
Views: 968
Reputation: 624
Create a new System.DateTime object. Initialize it with the current year and current month (which can be obtained from DateTime.Now). Set the day to 30 if it's September/April/June/November, or 31, 28, etc.
Now you have a DateTime object representing the last day of the month. You can use DateTime.DayOfWeek to check if the day is a Saturday or Sunday (or holiday).
You can use DateTime.AddDays(-N) to "wind back" the DateTime object by a single day, then check again if it's a Saturday or Sunday (or holiday).
Repeat for whatever Nth last day of the month check you need to make.
Upvotes: -1
Reputation: 11703
Based on the OP comments to my original answer, I decided to write another function as an exercise.
Here it is (again - not fully tested):
// Nth day should not be larger than 14 - I have tested it
bool Nth_BusinessDay(int NthDay, DateTime current)
{
// check we have NthDay larger than ZERO
if (NthDay < 1)
return false;
// make sure the taget date is just a date - no time component
DateTime target = current.Date;
// make sure the specialDay is not larger than the current days in the month
if (DateTime.DaysInMonth(target.Year, target.Month) > NthDay)
return false;
// start at the beginning
DateTime NthStart = new DateTime(target.Year, target.Month, 1);
// check if start date falls on the weekend
if (NthStart.DayOfWeek == DayOfWeek.Saturday)
NthStart = NthStart.AddDays(2); // jump TWO days to Monday
if (NthStart.DayOfWeek == DayOfWeek.Sunday)
NthStart = NthStart.AddDays(1); // jump ONE day to Monday
// now add our Nth day
NthStart = NthStart.AddDays(NthDay - 1);
// if we land on weekend after we adjusted for the Nth - push it by two days
if (NthStart.DayOfWeek == DayOfWeek.Saturday || NthStart.DayOfWeek == DayOfWeek.Sunday)
NthStart = NthStart.AddDays(2);
// start at the end and minus the Nth day
DateTime NthEnd = new DateTime(target.Year, target.Month, DateTime.DaysInMonth(target.Year, target.Month));
// check if the end date falls on the weekend - the difference here is the adjustment
if (NthEnd.DayOfWeek == DayOfWeek.Saturday)
NthEnd = NthEnd.AddDays(-1); // jump ONE day back to Friday
if (NthEnd.DayOfWeek == DayOfWeek.Sunday)
NthEnd = NthEnd.AddDays(-2); // jump TWO days back to Friday
// now subject our Nth day from the End
NthEnd = NthEnd.AddDays((NthDay - 1) * -1);
// again if we land on weekend - adjust by two days
if (NthStart.DayOfWeek == DayOfWeek.Saturday || NthStart.DayOfWeek == DayOfWeek.Sunday)
NthStart = NthStart.AddDays(2);
// check if our target day is one of the Nth day
if (NthStart == target || NthEnd == target)
return true;
return false;
}
And to use the function above:
void doTaskNthDay()
{
if (Nth_BusinessDay(5, DateTime.Now))
{
// do stuff
}
}
Below is my original answer left here for informational purposes.
I took the following code from: .NET Date Compare: Count the amount of working days since a date?. I haven't tested this code but you could try something like this:
int BuinessDayCount(DateTime targetDay)
{
// check if the target day is a weekend
if (targetDay.DayOfWeek == DayOfWeek.Saturday)
return -1;
if (targetDay.DayOfWeek == DayOfWeek.Sunday)
return -2;
// get the start of the month
DateTime start = new DateTime(targetDay.Year, targetDay.Month, 1);
// create a target without any time component
DateTime end = targetDay.Date;
int workingDays = 0;
while (start <= targetDay)
{
if (start.DayOfWeek != DayOfWeek.Saturday
&& start.DayOfWeek != DayOfWeek.Sunday)
{
workingDays++;
}
start = start.AddDays(1);
}
return workingDays;
}
Then in your code I would do the follow:
void doTask()
{
int businessDay = BuinessDayCount(DateTime.Now);
if (businessDay == 5 || businessDay == 25)
{
// do stuff
}
}
I think it will read better.
Upvotes: 3
Reputation: 784
I would do something like:
int numOfOccurredBusinessDays = 0; // this will include current business day
int businessDaysLeft = 0;
var currentDate = DateTime.Now;
var monthIterator = new DateTime(DateTime.Year, DateTime.Month, 1);
for (int i = 0; i < DateTime.DaysInMonth; ++i, monthIterator.AddDay(1))
{
if (monthIterator <= currentDate &&
!monthIterator.Date.ToString("D").Contains("Sat") &&
!monthIterator.Date.ToString("D").Contains("Sun"))
numOfOccurredBusinessDays++;
else if (monthIterator > currentDate &&
!monthIterator.Date.ToString("D").Contains("Sat") &&
!monthIterator.Date.ToString("D").Contains("Sun"))
businessDaysLeft++;
}
Upvotes: 1