ubuntunoob
ubuntunoob

Reputation: 249

How to check if the current day is the Nth or Nth from last business day of the month?

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

Answers (3)

cjcurrie
cjcurrie

Reputation: 624

  1. 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.

  2. 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).

  3. 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).

  4. Repeat for whatever Nth last day of the month check you need to make.

Upvotes: -1

Black Frog
Black Frog

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

czifro
czifro

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

Related Questions