Calculate the number of business days between two dates?
Asked Answered
I

41

132

In C#, how can I calculate the number of business (or weekdays) days between two dates?

Itinerate answered 24/10, 2009 at 5:22 Comment(3)
Here is an example in C# that also extends into getting hours as well. codeproject.com/KB/datetime/CalculatingBusinessHours.aspxSubclimax
Take a look at infopathdev.com/forums/t/7156.aspxPianette
so are you to exclude holidays?Billfold
A
142

I've had such a task before and I've got the solution. I would avoid enumerating all days in between when it's avoidable, which is the case here. I don't even mention creating a bunch of DateTime instances, as I saw in one of the answers above. This is really waste of processing power. Especially in the real world situation, when you have to examine time intervals of several months. See my code, with comments, below.

    /// <summary>
    /// Calculates number of business days, taking into account:
    ///  - weekends (Saturdays and Sundays)
    ///  - bank holidays in the middle of the week
    /// </summary>
    /// <param name="firstDay">First day in the time interval</param>
    /// <param name="lastDay">Last day in the time interval</param>
    /// <param name="bankHolidays">List of bank holidays excluding weekends</param>
    /// <returns>Number of business days during the 'span'</returns>
    public static int BusinessDaysUntil(this DateTime firstDay, DateTime lastDay, params DateTime[] bankHolidays)
    {
        firstDay = firstDay.Date;
        lastDay = lastDay.Date;
        if (firstDay > lastDay)
            throw new ArgumentException("Incorrect last day " + lastDay);

        TimeSpan span = lastDay - firstDay;
        int businessDays = span.Days + 1;
        int fullWeekCount = businessDays / 7;
        // find out if there are weekends during the time exceedng the full weeks
        if (businessDays > fullWeekCount*7)
        {
            // we are here to find out if there is a 1-day or 2-days weekend
            // in the time interval remaining after subtracting the complete weeks
            int firstDayOfWeek = (int) firstDay.DayOfWeek;
            int lastDayOfWeek = (int) lastDay.DayOfWeek;
            if (lastDayOfWeek < firstDayOfWeek)
                lastDayOfWeek += 7;
            if (firstDayOfWeek <= 6)
            {
                if (lastDayOfWeek >= 7)// Both Saturday and Sunday are in the remaining time interval
                    businessDays -= 2;
                else if (lastDayOfWeek >= 6)// Only Saturday is in the remaining time interval
                    businessDays -= 1;
            }
            else if (firstDayOfWeek <= 7 && lastDayOfWeek >= 7)// Only Sunday is in the remaining time interval
                businessDays -= 1;
        }

        // subtract the weekends during the full weeks in the interval
        businessDays -= fullWeekCount + fullWeekCount;

        // subtract the number of bank holidays during the time interval
        foreach (DateTime bankHoliday in bankHolidays)
        {
            DateTime bh = bankHoliday.Date;
            if (firstDay <= bh && bh <= lastDay)
                --businessDays;
        }

        return businessDays;
    }

Edit by Slauma, August 2011

Great answer! There is little bug though. I take the freedom to edit this answer since the answerer is absent since 2009.

The code above assumes that DayOfWeek.Sunday has the value 7 which is not the case. The value is actually 0. It leads to a wrong calculation if for example firstDay and lastDay are both the same Sunday. The method returns 1 in this case but it should be 0.

Easiest fix for this bug: Replace in the code above the lines where firstDayOfWeek and lastDayOfWeek are declared by the following:

int firstDayOfWeek = firstDay.DayOfWeek == DayOfWeek.Sunday 
    ? 7 : (int)firstDay.DayOfWeek;
int lastDayOfWeek = lastDay.DayOfWeek == DayOfWeek.Sunday
    ? 7 : (int)lastDay.DayOfWeek;

Now the result is:

  • Friday to Friday -> 1
  • Saturday to Saturday -> 0
  • Sunday to Sunday -> 0
  • Friday to Saturday -> 1
  • Friday to Sunday -> 1
  • Friday to Monday -> 2
  • Saturday to Monday -> 1
  • Sunday to Monday -> 1
  • Monday to Monday -> 1
Astrograph answered 24/10, 2009 at 22:35 Comment(10)
Also make sure that bank holidays as follows: if (firstDay <= bh && bh <= lastDay && bh.IsWorkingDay())Ridinger
Thanks for the method. Although, I had to add the following to the bank holidays substraction/iteration if-statement: && !(bh.DayOfWeek == DayOfWeek.Sunday || bh.DayOfWeek == DayOfWeek.Saturday), else it would substract the same day twice, if a holiday falls in a weekend.Baroda
I changed the last loop for a Linq statement: businessDays -= bankHolidays.Select(bankHoliday => bankHoliday.Date).Count(bh => firstDay <= bh && bh <= lastDay);Evelunn
The first day of the week can change according to user settings.Milky
Also they are countries that don't have the weekend in Saturday, Sunday. See this link for more info: en.wikipedia.org/wiki/Workweek_and_weekendSupervise
Friday -> Saturday returns 2 days, obviously incorrect. The code can be much shorter too, look at the other answer below.Quinquevalent
As mentioned by MrFox, FirstDayOfWeek (learn.microsoft.com/en-us/dotnet/api/…) property is assumed to be Monday for this solution. This is the cause of the issue described in the update from 2011. It appears the default is Sunday, so by default this solution won't give accurate results.Indre
whats businessDays -= fullWeekCount + fullWeekCount; doing ? should it be businessDays -= fullWeekCount * 5?Defamation
How much processing power is wasted by creating DateTime instances? Is it really that bad? It feels like an assumption.Goiter
this fails my unit test with "02-10-2018" - "03-31-2021" returns 817. But it should 818Clinquant
B
133

Ok. I think it's time to post the right answer:

public static double GetBusinessDays(DateTime startD, DateTime endD)
{
    double calcBusinessDays =
        1 + ((endD - startD).TotalDays * 5 -
        (startD.DayOfWeek - endD.DayOfWeek) * 2) / 7;

    if (endD.DayOfWeek == DayOfWeek.Saturday) calcBusinessDays--;
    if (startD.DayOfWeek == DayOfWeek.Sunday) calcBusinessDays--;

    return calcBusinessDays;
}

Original Source:

http://alecpojidaev.wordpress.com/2009/10/29/work-days-calculation-with-c/

Blakeney answered 29/10, 2009 at 20:38 Comment(17)
Good work, but perhaps use the DayOfWeek enums themselves rather than cast them to ints?Sympathetic
Seriously, best solution out there. Cheers AlecGlaswegian
@xanadont just remove the initial 1+Ingrowth
Comment removed as the error I was commenting on was in my modified version, not the original. Oops.Verret
Note that even though this function returns a double, it should only be trusted to give whole business days. It does not return the correct answer for fractional days when times are involved.Ingrowth
Just to remark, with the '1+' it assumes start of first day until end of last day, without the '1+' it assumes end of first day until end of last day. Took me a while to figure that out, since I was assuming start of first day until start of last day, which made more sense to me.Blunger
This answer is the best answer! The currently proposed answer has a bug (Friday -> Saturday == 2 days??), this answer is shorter and much better.Quinquevalent
This doesn't give the same answer as Excel's NetworkDays function. In microsoft the days start with sunday which is enumerated as 0. Is this the reason why the numbers are between 0-3 days out ?Kries
This is NOT the correct answer. Days can be out by upto 4. Almost right, doesn't take account of when the start and end day wrap around the weekend, which is the trickiest bit. The start - end shouldn't be inside the parentheses either. It's got nothing to do with the problem. 60% of the time this solution is WRONG.Kries
If you pass the same date for start and end, it return 1, be very careful trusting this codeSandman
Yes, business days between the same date is 1 - that's perverse and not an expected answer. Seems to work OK if function returns -1 - at least it is complmentary to the add business days logic on his website.Heavenly
Pretty fast. Thank you!Prouty
@Stefan, I have no idea why I originally wrote that. It seems incorrect now, I've deleted my comment.Lancelle
Holidays are not respected in this solution.Goiter
I wrote unit tests and this code gives wrong outputs. For Example start=2021-01-02, end=2021-01-10 Result: Expected=5, Actual=8Dialogize
@Dialogize I got 5 with the same dates :) I also got 6 days between 2022-08-01 and 2022-08-08. Seems like it wrapped nicely around that weekend.Elsie
In reaction on comment from @Kries (Feb 24, 2017), I wrote some tests (xUnit) gist.github.com/tkouba/2295988ee4388973f35414cf4b8abf69 and it looks good.Helmsman
R
58

I know this question is already solved, but I thought I could provide a more straightforward-looking answer that may help other visitors in the future.

Here's my take at it:

public int GetWorkingDays(DateTime from, DateTime to)
{
    var dayDifference = (int)to.Subtract(from).TotalDays;
    return Enumerable
        .Range(1, dayDifference)
        .Select(x => from.AddDays(x))
        .Count(x => x.DayOfWeek != DayOfWeek.Saturday && x.DayOfWeek != DayOfWeek.Sunday);
}

This was my original submission:

public int GetWorkingDays(DateTime from, DateTime to)
{
    var totalDays = 0;
    for (var date = from; date < to; date = date.AddDays(1))
    {
        if (date.DayOfWeek != DayOfWeek.Saturday
            && date.DayOfWeek != DayOfWeek.Sunday)
            totalDays++;
    }

    return totalDays;
}
Radiosensitive answered 29/4, 2012 at 20:28 Comment(7)
"where" could be "count" to shorten itRabaul
Much clearer, and the enumerated solutions lend themselves to eliminating bank holidays. They are much slower in bulk though; In LINQPad calculating working days for 90 day gaps in a 1 million iteration loop takes 10s using this solution, and only about 0.2s using the accepted answer or Alec Pojidaev's much nicer one.Verret
To be inclusive, the code should be: return Enumerable .Range(0, dayDifference + 1) ...Sodomite
does not return days in the past. Like -18 working days.Copeland
@Copeland This assumes that to > from. Maybe that's the problem?Radiosensitive
@Radiosensitive I just believe that good function should return something meaningful for all valid inputs. So you don't need to do check before calling the functionCopeland
@Copeland I don't think having to < from is a valid input. -18 working days is not a valid response either. If anything, it should throw an exception or return 0.Radiosensitive
P
23

Define an Extension Method on DateTime like so:

public static class DateTimeExtensions
{
    public static bool IsWorkingDay(this DateTime date)
    {
        return date.DayOfWeek != DayOfWeek.Saturday
            && date.DayOfWeek != DayOfWeek.Sunday;
    }
}

Then, use is within a Where clause to filter a broader list of dates:

var allDates = GetDates(); // method which returns a list of dates

// filter dates by working day's  
var countOfWorkDays = allDates
     .Where(day => day.IsWorkingDay())
     .Count() ;
Parvis answered 24/10, 2009 at 5:43 Comment(5)
Would you not just go ahead and extend timespan as well so you can use that - since he did say he wanted to use the distance between two dates and not a list of dates?Subclimax
The distance between the two dates is the number of day between, so the Count() is sufficient.Ashantiashbaugh
I'm not sure why this is a suitable answer...he doesn't have a list of individual days, he has two dates and he wants to find the number of business days between them. In order to use this solution you'd have to provide another function that produced a list of every date between the twyp.Toniatonic
adam, this is a simple example with the minimum amount of code that is needed to demonstrate a concept. In my original answer, I also included a loop which popultated the allDates list which I have since abstracted away into the "GetDates" function. The IsWorkingDay test could easily be moved out of the LINQ statement and into that loop. I personally like how it is now though because it is very human readable as to what is happening.Parvis
Could be shorted by changing Where to Count, and eliminating CountGrandioso
A
13

I used the following code to also take in to account bank holidays:

public class WorkingDays
{
    public List<DateTime> GetHolidays()
    {
        var client = new WebClient();
        var json = client.DownloadString("https://www.gov.uk/bank-holidays.json");
        var js = new JavaScriptSerializer();
        var holidays = js.Deserialize <Dictionary<string, Holidays>>(json);
        return holidays["england-and-wales"].events.Select(d => d.date).ToList();
    }

    public int GetWorkingDays(DateTime from, DateTime to)
    {
        var totalDays = 0;
        var holidays = GetHolidays();
        for (var date = from.AddDays(1); date <= to; date = date.AddDays(1))
        {
            if (date.DayOfWeek != DayOfWeek.Saturday
                && date.DayOfWeek != DayOfWeek.Sunday
                && !holidays.Contains(date))
                totalDays++;
        }

        return totalDays;
    }
}

public class Holidays
{
    public string division { get; set; }
    public List<Event> events { get; set; }
}

public class Event
{
    public DateTime date { get; set; }
    public string notes { get; set; }
    public string title { get; set; }
}

And Unit Tests:

[TestClass]
public class WorkingDays
{
    [TestMethod]
    public void SameDayIsZero()
    {
        var service = new WorkingDays();

        var from = new DateTime(2013, 8, 12);

        Assert.AreEqual(0, service.GetWorkingDays(from, from));

    }

    [TestMethod]
    public void CalculateDaysInWorkingWeek()
    {
        var service = new WorkingDays();

        var from = new DateTime(2013, 8, 12);
        var to = new DateTime(2013, 8, 16);

        Assert.AreEqual(4, service.GetWorkingDays(from, to), "Mon - Fri = 4");

        Assert.AreEqual(1, service.GetWorkingDays(from, new DateTime(2013, 8, 13)), "Mon - Tues = 1");
    }

    [TestMethod]
    public void NotIncludeWeekends()
    {
        var service = new WorkingDays();

        var from = new DateTime(2013, 8, 9);
        var to = new DateTime(2013, 8, 16);

        Assert.AreEqual(5, service.GetWorkingDays(from, to), "Fri - Fri = 5");

        Assert.AreEqual(2, service.GetWorkingDays(from, new DateTime(2013, 8, 13)), "Fri - Tues = 2");
        Assert.AreEqual(1, service.GetWorkingDays(from, new DateTime(2013, 8, 12)), "Fri - Mon = 1");
    }

    [TestMethod]
    public void AccountForHolidays()
    {
        var service = new WorkingDays();

        var from = new DateTime(2013, 8, 23);

        Assert.AreEqual(0, service.GetWorkingDays(from, new DateTime(2013, 8, 26)), "Fri - Mon = 0");

        Assert.AreEqual(1, service.GetWorkingDays(from, new DateTime(2013, 8, 27)), "Fri - Tues = 1");
    }
}
Armin answered 16/8, 2013 at 14:1 Comment(1)
why do you start counting by adding 1 days to "from" @ for (var date = from.AddDays(1); date <= to; date = date.AddDays(1)) ?Wall
P
7

I searched a lot for a, easy to digest, algorithm to calculate the working days between 2 dates, and also to exclude the national holidays, and finally I decide to go with this approach:

public static int NumberOfWorkingDaysBetween2Dates(DateTime start,DateTime due,IEnumerable<DateTime> holidays)
        {
            var dic = new Dictionary<DateTime, DayOfWeek>();
            var totalDays = (due - start).Days;
            for (int i = 0; i < totalDays + 1; i++)
            {
                if (!holidays.Any(x => x == start.AddDays(i)))
                    dic.Add(start.AddDays(i), start.AddDays(i).DayOfWeek);
            }

            return dic.Where(x => x.Value != DayOfWeek.Saturday && x.Value != DayOfWeek.Sunday).Count();
        } 

Basically I wanted to go with each date and evaluate my conditions:

  1. Is not Saturday
  2. Is not Sunday
  3. Is not national holiday

but also I wanted to avoid iterating dates.

By running and measuring the time need it to evaluate 1 full year, I go the following result:

static void Main(string[] args)
        {
            var start = new DateTime(2017, 1, 1);
            var due = new DateTime(2017, 12, 31);

            var sw = Stopwatch.StartNew();
            var days = NumberOfWorkingDaysBetween2Dates(start, due,NationalHolidays());
            sw.Stop();

            Console.WriteLine($"Total working days = {days} --- time: {sw.Elapsed}");
            Console.ReadLine();

            // result is:
           // Total working days = 249-- - time: 00:00:00.0269087
        }

Edit: a new method more simple:

public static int ToBusinessWorkingDays(this DateTime start, DateTime due, DateTime[] holidays)
        {
            return Enumerable.Range(0, (due - start).Days)
                            .Select(a => start.AddDays(a))
                            .Where(a => a.DayOfWeek != DayOfWeek.Sunday)
                            .Where(a => a.DayOfWeek != DayOfWeek.Saturday)
                            .Count(a => !holidays.Any(x => x == a));

        }
Platinocyanide answered 31/12, 2016 at 8:6 Comment(0)
C
6

This solution avoids iteration, works for both +ve and -ve weekday differences and includes a unit test suite to regression against the slower method of counting weekdays. I've also include a concise method to add weekdays also works in the same non-iterative way.

Unit tests cover a few thousand date combinations in order to exhaustively test all start/end weekday combinations with both small and large date ranges.

Important: We make the assumption that we are counting days by excluding the start date and including the end date. This is important when counting weekdays as the specific start/end days that you include/exclude affect the result. This also ensures that the difference between two equal days is always zero and that we only include full working days as typically you want the answer to be correct for any time on the current start date (often today) and include the full end date (e.g. a due date).

NOTE: This code needs an additional adjustment for holidays but in keeping with the above assumption, this code must exclude holidays on the start date.

Add weekdays:

private static readonly int[,] _addOffset = 
{
  // 0  1  2  3  4
    {0, 1, 2, 3, 4}, // Su  0
    {0, 1, 2, 3, 4}, // M   1
    {0, 1, 2, 3, 6}, // Tu  2
    {0, 1, 4, 5, 6}, // W   3
    {0, 1, 4, 5, 6}, // Th  4
    {0, 3, 4, 5, 6}, // F   5
    {0, 2, 3, 4, 5}, // Sa  6
};

public static DateTime AddWeekdays(this DateTime date, int weekdays)
{
    int extraDays = weekdays % 5;
    int addDays = weekdays >= 0
        ? (weekdays / 5) * 7 + _addOffset[(int)date.DayOfWeek, extraDays]
        : (weekdays / 5) * 7 - _addOffset[6 - (int)date.DayOfWeek, -extraDays];
    return date.AddDays(addDays);
}

Compute weekday difference:

static readonly int[,] _diffOffset = 
{
  // Su M  Tu W  Th F  Sa
    {0, 1, 2, 3, 4, 5, 5}, // Su
    {4, 0, 1, 2, 3, 4, 4}, // M 
    {3, 4, 0, 1, 2, 3, 3}, // Tu
    {2, 3, 4, 0, 1, 2, 2}, // W 
    {1, 2, 3, 4, 0, 1, 1}, // Th
    {0, 1, 2, 3, 4, 0, 0}, // F 
    {0, 1, 2, 3, 4, 5, 0}, // Sa
};

public static int GetWeekdaysDiff(this DateTime dtStart, DateTime dtEnd)
{
    int daysDiff = (int)(dtEnd - dtStart).TotalDays;
    return daysDiff >= 0
        ? 5 * (daysDiff / 7) + _diffOffset[(int) dtStart.DayOfWeek, (int) dtEnd.DayOfWeek]
        : 5 * (daysDiff / 7) - _diffOffset[6 - (int) dtStart.DayOfWeek, 6 - (int) dtEnd.DayOfWeek];
}

I found that most other solutions on stack overflow were either slow (iterative) or overly complex and many were just plain incorrect. Moral of the story is ... Don't trust it unless you've exhaustively tested it!!

Unit tests based on NUnit Combinatorial testing and ShouldBe NUnit extension.

[TestFixture]
public class DateTimeExtensionsTests
{
    /// <summary>
    /// Exclude start date, Include end date
    /// </summary>
    /// <param name="dtStart"></param>
    /// <param name="dtEnd"></param>
    /// <returns></returns>
    private IEnumerable<DateTime> GetDateRange(DateTime dtStart, DateTime dtEnd)
    {
        Console.WriteLine(@"dtStart={0:yy-MMM-dd ddd}, dtEnd={1:yy-MMM-dd ddd}", dtStart, dtEnd);

        TimeSpan diff = dtEnd - dtStart;
        Console.WriteLine(diff);

        if (dtStart <= dtEnd)
        {
            for (DateTime dt = dtStart.AddDays(1); dt <= dtEnd; dt = dt.AddDays(1))
            {
                Console.WriteLine(@"dt={0:yy-MMM-dd ddd}", dt);
                yield return dt;
            }
        }
        else
        {
            for (DateTime dt = dtStart.AddDays(-1); dt >= dtEnd; dt = dt.AddDays(-1))
            {
                Console.WriteLine(@"dt={0:yy-MMM-dd ddd}", dt);
                yield return dt;
            }
        }
    }

    [Test, Combinatorial]
    public void TestGetWeekdaysDiff(
        [Values(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 20, 30)]
        int startDay,
        [Values(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 20, 30)]
        int endDay,
        [Values(7)]
        int startMonth,
        [Values(7)]
        int endMonth)
    {
        // Arrange
        DateTime dtStart = new DateTime(2016, startMonth, startDay);
        DateTime dtEnd = new DateTime(2016, endMonth, endDay);

        int nDays = GetDateRange(dtStart, dtEnd)
            .Count(dt => dt.DayOfWeek != DayOfWeek.Saturday && dt.DayOfWeek != DayOfWeek.Sunday);

        if (dtEnd < dtStart) nDays = -nDays;

        Console.WriteLine(@"countBusDays={0}", nDays);

        // Act / Assert
        dtStart.GetWeekdaysDiff(dtEnd).ShouldBe(nDays);
    }

    [Test, Combinatorial]
    public void TestAddWeekdays(
        [Values(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 20, 30)]
        int startDay,
        [Values(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 20, 30)]
        int weekdays)
    {
        DateTime dtStart = new DateTime(2016, 7, startDay);
        DateTime dtEnd1 = dtStart.AddWeekdays(weekdays);     // ADD
        dtStart.GetWeekdaysDiff(dtEnd1).ShouldBe(weekdays);  

        DateTime dtEnd2 = dtStart.AddWeekdays(-weekdays);    // SUBTRACT
        dtStart.GetWeekdaysDiff(dtEnd2).ShouldBe(-weekdays);
    }
}
Chumash answered 8/6, 2016 at 5:12 Comment(1)
The idea for this came from an SQL solution I found on stack overflow. Their idea was solid but sadly it too had a bug. It worked for +ve values but their lookup table mapping was incorrect for -ve values.Zacarias
R
5

Well this has been beaten to death. :) However I'm still going to provide another answer because I needed something a bit different. This solution is different in that it returns a Business TimeSpan between the start and end, and you can set the business hours of the day, and add holidays. So you can use it to calculate if it happens within a day, across days, over weekends, and even holidays. And you can get just the business days or not by just getting what you need from the returned TimeSpan object. And the way it uses lists of days, you can see how very easy it would be to add the list of non-work days if it's not the typical Sat and Sun. And I tested for a year, and it seems super fast.

I just hope the pasting of the code is accurate. But I know it works.

public static TimeSpan GetBusinessTimespanBetween(
    DateTime start, DateTime end,
    TimeSpan workdayStartTime, TimeSpan workdayEndTime,
    List<DateTime> holidays = null)
{
    if (end < start)
        throw new ArgumentException("start datetime must be before end datetime.");

    // Just create an empty list for easier coding.
    if (holidays == null) holidays = new List<DateTime>();

    if (holidays.Where(x => x.TimeOfDay.Ticks > 0).Any())
        throw new ArgumentException("holidays can not have a TimeOfDay, only the Date.");

    var nonWorkDays = new List<DayOfWeek>() { DayOfWeek.Saturday, DayOfWeek.Sunday };

    var startTime = start.TimeOfDay;

    // If the start time is before the starting hours, set it to the starting hour.
    if (startTime < workdayStartTime) startTime = workdayStartTime;

    var timeBeforeEndOfWorkDay = workdayEndTime - startTime;

    // If it's after the end of the day, then this time lapse doesn't count.
    if (timeBeforeEndOfWorkDay.TotalSeconds < 0) timeBeforeEndOfWorkDay = new TimeSpan();
    // If start is during a non work day, it doesn't count.
    if (nonWorkDays.Contains(start.DayOfWeek)) timeBeforeEndOfWorkDay = new TimeSpan();
    else if (holidays.Contains(start.Date)) timeBeforeEndOfWorkDay = new TimeSpan();

    var endTime = end.TimeOfDay;

    // If the end time is after the ending hours, set it to the ending hour.
    if (endTime > workdayEndTime) endTime = workdayEndTime;

    var timeAfterStartOfWorkDay = endTime - workdayStartTime;

    // If it's before the start of the day, then this time lapse doesn't count.
    if (timeAfterStartOfWorkDay.TotalSeconds < 0) timeAfterStartOfWorkDay = new TimeSpan();
    // If end is during a non work day, it doesn't count.
    if (nonWorkDays.Contains(end.DayOfWeek)) timeAfterStartOfWorkDay = new TimeSpan();
    else if (holidays.Contains(end.Date)) timeAfterStartOfWorkDay = new TimeSpan();

    // Easy scenario if the times are during the day day.
    if (start.Date.CompareTo(end.Date) == 0)
    {
        if (nonWorkDays.Contains(start.DayOfWeek)) return new TimeSpan();
        else if (holidays.Contains(start.Date)) return new TimeSpan();
        return endTime - startTime;
    }
    else
    {
        var timeBetween = end - start;
        var daysBetween = (int)Math.Floor(timeBetween.TotalDays);
        var dailyWorkSeconds = (int)Math.Floor((workdayEndTime - workdayStartTime).TotalSeconds);

        var businessDaysBetween = 0;

        // Now the fun begins with calculating the actual Business days.
        if (daysBetween > 0)
        {
            var nextStartDay = start.AddDays(1).Date;
            var dayBeforeEnd = end.AddDays(-1).Date;
            for (DateTime d = nextStartDay; d <= dayBeforeEnd; d = d.AddDays(1))
            {
                if (nonWorkDays.Contains(d.DayOfWeek)) continue;
                else if (holidays.Contains(d.Date)) continue;
                businessDaysBetween++;
            }
        }

        var dailyWorkSecondsToAdd = dailyWorkSeconds * businessDaysBetween;

        var output = timeBeforeEndOfWorkDay + timeAfterStartOfWorkDay;
        output = output + new TimeSpan(0, 0, dailyWorkSecondsToAdd);

        return output;
    }
}

And here is test code: Note that you just have to put this function in a class called DateHelper for the test code to work.

[TestMethod]
public void TestGetBusinessTimespanBetween()
{
    var workdayStart = new TimeSpan(8, 0, 0);
    var workdayEnd = new TimeSpan(17, 0, 0);

    var holidays = new List<DateTime>()
    {
        new DateTime(2018, 1, 15), // a Monday
        new DateTime(2018, 2, 15) // a Thursday
    };

    var testdata = new[]
    {
        new
        {
            expectedMinutes = 0,
            start = new DateTime(2016, 10, 19, 9, 50, 0),
            end = new DateTime(2016, 10, 19, 9, 50, 0)
        },
        new
        {
            expectedMinutes = 10,
            start = new DateTime(2016, 10, 19, 9, 50, 0),
            end = new DateTime(2016, 10, 19, 10, 0, 0)
        },
        new
        {
            expectedMinutes = 5,
            start = new DateTime(2016, 10, 19, 7, 50, 0),
            end = new DateTime(2016, 10, 19, 8, 5, 0)
        },
        new
        {
            expectedMinutes = 5,
            start = new DateTime(2016, 10, 19, 16, 55, 0),
            end = new DateTime(2016, 10, 19, 17, 5, 0)
        },
        new
        {
            expectedMinutes = 15,
            start = new DateTime(2016, 10, 19, 16, 50, 0),
            end = new DateTime(2016, 10, 20, 8, 5, 0)
        },
        new
        {
            expectedMinutes = 10,
            start = new DateTime(2016, 10, 19, 16, 50, 0),
            end = new DateTime(2016, 10, 20, 7, 55, 0)
        },
        new
        {
            expectedMinutes = 5,
            start = new DateTime(2016, 10, 19, 17, 10, 0),
            end = new DateTime(2016, 10, 20, 8, 5, 0)
        },
        new
        {
            expectedMinutes = 0,
            start = new DateTime(2016, 10, 19, 17, 10, 0),
            end = new DateTime(2016, 10, 20, 7, 5, 0)
        },
        new
        {
            expectedMinutes = 545,
            start = new DateTime(2016, 10, 19, 12, 10, 0),
            end = new DateTime(2016, 10, 20, 12, 15, 0)
        },
        // Spanning multiple weekdays
        new
        {
            expectedMinutes = 835,
            start = new DateTime(2016, 10, 19, 12, 10, 0),
            end = new DateTime(2016, 10, 21, 8, 5, 0)
        },
        // Spanning multiple weekdays
        new
        {
            expectedMinutes = 1375,
            start = new DateTime(2016, 10, 18, 12, 10, 0),
            end = new DateTime(2016, 10, 21, 8, 5, 0)
        },
        // Spanning from a Thursday to a Tuesday, 5 mins short of complete day.
        new
        {
            expectedMinutes = 1615,
            start = new DateTime(2016, 10, 20, 12, 10, 0),
            end = new DateTime(2016, 10, 25, 12, 5, 0)
        },
        // Spanning from a Thursday to a Tuesday, 5 mins beyond complete day.
        new
        {
            expectedMinutes = 1625,
            start = new DateTime(2016, 10, 20, 12, 10, 0),
            end = new DateTime(2016, 10, 25, 12, 15, 0)
        },
        // Spanning from a Friday to a Monday, 5 mins beyond complete day.
        new
        {
            expectedMinutes = 545,
            start = new DateTime(2016, 10, 21, 12, 10, 0),
            end = new DateTime(2016, 10, 24, 12, 15, 0)
        },
        // Spanning from a Friday to a Monday, 5 mins short complete day.
        new
        {
            expectedMinutes = 535,
            start = new DateTime(2016, 10, 21, 12, 10, 0),
            end = new DateTime(2016, 10, 24, 12, 5, 0)
        },
        // Spanning from a Saturday to a Monday, 5 mins short complete day.
        new
        {
            expectedMinutes = 245,
            start = new DateTime(2016, 10, 22, 12, 10, 0),
            end = new DateTime(2016, 10, 24, 12, 5, 0)
        },
        // Spanning from a Saturday to a Sunday, 5 mins beyond complete day.
        new
        {
            expectedMinutes = 0,
            start = new DateTime(2016, 10, 22, 12, 10, 0),
            end = new DateTime(2016, 10, 23, 12, 15, 0)
        },
        // Times within the same Saturday.
        new
        {
            expectedMinutes = 0,
            start = new DateTime(2016, 10, 22, 12, 10, 0),
            end = new DateTime(2016, 10, 23, 12, 15, 0)
        },
        // Spanning from a Saturday to the Sunday next week.
        new
        {
            expectedMinutes = 2700,
            start = new DateTime(2016, 10, 22, 12, 10, 0),
            end = new DateTime(2016, 10, 30, 12, 15, 0)
        },
        // Spanning a year.
        new
        {
            expectedMinutes = 143355,
            start = new DateTime(2016, 10, 22, 12, 10, 0),
            end = new DateTime(2017, 10, 30, 12, 15, 0)
        },
        // Spanning a year with 2 holidays.
        new
        {
            expectedMinutes = 142815,
            start = new DateTime(2017, 10, 22, 12, 10, 0),
            end = new DateTime(2018, 10, 30, 12, 15, 0)
        },
    };

    foreach (var item in testdata)
    {
        Assert.AreEqual(item.expectedMinutes,
            DateHelper.GetBusinessTimespanBetween(
                item.start, item.end,
                workdayStart, workdayEnd,
                holidays)
                .TotalMinutes);
    }
}
Raddled answered 20/10, 2016 at 2:17 Comment(0)
E
4

Here's some code for that purpose, with swedish holidays but you can adapt what holidays to count. Note that I added a limit you might want to remove, but it was for a web-based system and I didnt want anyone to enter some huge date to hog the process

  public static int GetWorkdays(DateTime from ,DateTime to)
    {
        int limit = 9999;
        int counter = 0;
        DateTime current = from;
        int result = 0;

        if (from > to)
        {
            DateTime temp = from;
            from = to;
            to = temp;
        }

        if (from >= to)
        {
            return 0;
        }


        while (current <= to && counter < limit)
        {
            if (IsSwedishWorkday(current))
            {
                result++;
            }
            current = current.AddDays(1);
            counter++;

        }
        return result;
    }


    public static bool IsSwedishWorkday(DateTime date)
    {
        return (!IsSwedishHoliday(date) && date.DayOfWeek != DayOfWeek.Saturday && date.DayOfWeek != DayOfWeek.Sunday);
    }

    public static bool IsSwedishHoliday(DateTime date)
    {
        return (
        IsSameDay(GetEpiphanyDay(date.Year), date) ||
        IsSameDay(GetMayDay(date.Year), date) ||
        IsSameDay(GetSwedishNationalDay(date.Year), date) ||
        IsSameDay(GetChristmasDay(date.Year), date) ||
        IsSameDay(GetBoxingDay(date.Year), date) ||
        IsSameDay(GetGoodFriday(date.Year), date) ||
        IsSameDay(GetAscensionDay(date.Year), date) ||
        IsSameDay(GetAllSaintsDay(date.Year), date) ||
        IsSameDay(GetMidsummersDay(date.Year), date) ||
        IsSameDay(GetPentecostDay(date.Year), date) ||
        IsSameDay(GetEasterMonday(date.Year), date) ||
        IsSameDay(GetNewYearsDay(date.Year), date) ||
        IsSameDay(GetEasterDay(date.Year), date)
        );
    }

    // Trettondagen
    public static DateTime GetEpiphanyDay(int year)
    {
        return new DateTime(year, 1, 6);
    }

    // Första maj
    public static DateTime GetMayDay(int year)
    {
        return new DateTime(year,5,1);
    }

    // Juldagen
    public static DateTime GetSwedishNationalDay(int year)
    {
        return new DateTime(year, 6, 6);
    }


    // Juldagen
    public static DateTime GetNewYearsDay(int year)
    {
        return new DateTime(year,1,1);
    }

    // Juldagen
    public static DateTime GetChristmasDay(int year)
    {
        return new DateTime(year,12,25);
    }

    // Annandag jul
    public static DateTime GetBoxingDay(int year)
    {
        return new DateTime(year, 12, 26);
    }


    // Långfredagen
    public static DateTime GetGoodFriday(int year)
    {
        return GetEasterDay(year).AddDays(-3);
    }

    // Kristi himmelsfärdsdag
    public static DateTime GetAscensionDay(int year)
    {
        return GetEasterDay(year).AddDays(5*7+4);
    }

    // Midsommar
    public static DateTime GetAllSaintsDay(int year)
    {
        DateTime result = new DateTime(year,10,31);
        while (result.DayOfWeek != DayOfWeek.Saturday)
        {
            result = result.AddDays(1);
        }
        return result;
    }

    // Midsommar
    public static DateTime GetMidsummersDay(int year)
    {
        DateTime result = new DateTime(year, 6, 20);
        while (result.DayOfWeek != DayOfWeek.Saturday)
        {
            result = result.AddDays(1);
        }
        return result;
    }

    // Pingstdagen
    public static DateTime GetPentecostDay(int year)
    {
        return GetEasterDay(year).AddDays(7 * 7);
    }

    // Annandag påsk
    public static DateTime GetEasterMonday(int year)
    {
        return GetEasterDay(year).AddDays(1);
    }
    public static DateTime GetEasterDay(int y)
    {
        double c;
        double n;
        double k;
        double i;
        double j;
        double l;
        double m;
        double d;
        c = System.Math.Floor(y / 100.0);
        n = y - 19 * System.Math.Floor(y / 19.0);
        k = System.Math.Floor((c - 17) / 25.0);
        i = c - System.Math.Floor(c / 4) - System.Math.Floor((c - k) / 3) + 19 * n + 15;
        i = i - 30 * System.Math.Floor(i / 30);
        i = i - System.Math.Floor(i / 28) * (1 - System.Math.Floor(i / 28) * System.Math.Floor(29 / (i + 1)) * System.Math.Floor((21 - n) / 11));
        j = y + System.Math.Floor(y / 4.0) + i + 2 - c + System.Math.Floor(c / 4);
        j = j - 7 * System.Math.Floor(j / 7);
        l = i - j;
        m = 3 + System.Math.Floor((l + 40) / 44);// month
        d = l + 28 - 31 * System.Math.Floor(m / 4);// day

        double days = ((m == 3) ? d : d + 31);

        DateTime result = new DateTime(y, 3, 1).AddDays(days-1);

        return result;
    }
Elicia answered 24/10, 2009 at 7:44 Comment(2)
function issamedate is missing but is simply public static bool IsSameDay(DateTime date1, DateTime date2) { return date1.Date == date2.Date; }Ichthyic
You could use an int array lookup table instead of instantiating new Date objects.Quillon
C
4

Here's a quick sample code. It's a class method, so will only work inside of your class. If you want it to be static, change the signature to private static (or public static).

    private IEnumerable<DateTime> GetWorkingDays(DateTime sd, DateTime ed)
    {
        for (var d = sd; d <= ed; d = d.AddDays(1))
            if (d.DayOfWeek != DayOfWeek.Saturday && d.DayOfWeek != DayOfWeek.Sunday)
                yield return d;
    }

This method creates a loop variable d, initializes it to the start day, sd, then increments by one day each iteration (d = d.AddDays(1)).

It returns the desired values using yield, which creates an iterator. The cool thing about iterators is that they don't hold all of the values of the IEnumerable in memory, only calling each one sequentially. This means that you can call this method from the dawn of time to now without having to worry about running out of memory.

Conjuncture answered 28/5, 2015 at 15:40 Comment(1)
This method doesn't return the number of business days between two dates, it returns the business dates between two dates. The code you are proposing is very clean and I like the usage of yield, but it doesn't answer the question.Itinerate
C
4

Works and without loops

This method doesn't use any loops and is actually quite simple. It expands the date range to full weeks since we know that each week has 5 business days. It then uses a lookup table to find the number of business days to subtract from the start and end to get the right result. I've expanded out the calculation to help show what's going on, but the whole thing could be condensed into a single line if needed.

Anyway, this works for me and so I thought I'd post it here in case it might help others. Happy coding.

Calculation

  • t : Total number of days between dates (1 if min = max)
  • a + b : Extra days needed to expand total to full weeks
  • k : 1.4 is number of weekdays per week, i.e., (t / 7) * 5
  • c : Number of weekdays to subtract from the total
  • m : A lookup table used to find the value of "c" for each day of the week

Culture

Code assumes a Monday to Friday work week. For other cultures, such as Sunday to Thursday, you'll need to offset the dates prior to calculation.

Method

public int Weekdays(DateTime min, DateTime max) 
{       
        if (min.Date > max.Date) throw new Exception("Invalid date span");
        var t = (max.AddDays(1).Date - min.Date).TotalDays;
        var a = (int) min.DayOfWeek;
        var b = 6 - (int) max.DayOfWeek;
        var k = 1.4;
        var m = new int[]{0, 0, 1, 2, 3, 4, 5}; 
        var c = m[a] + m[b];
        return (int)((t + a + b) / k) - c;
}
Cimino answered 28/6, 2018 at 22:4 Comment(1)
how can you got K with value 1.4?Nett
I
3

This method returns the number of business days between two dates:

Here I use the DayOfWeek enum for checking weekends.

        private static int BusinessDaysLeft(DateTime first, DateTime last)
        {
            var count = 0;

            while (first.Date != last.Date)
            {
                if(first.DayOfWeek != DayOfWeek.Saturday && first.DayOfWeek != DayOfWeek.Sunday)
                    count++;
                
                first = first.AddDays(1);
            }

            return count;
        }
Interplay answered 12/5, 2021 at 17:18 Comment(0)
S
1

I think none of the above answers are actually correct. None of them solves all the special cases such as when the dates starts and ends on the middle of a weekend, when the date starts on a Friday and ends on next Monday, etc. On top of that, they all round the calculations to whole days, so if the start date is in the middle of a saturday for example, it will substract a whole day from the working days, giving wrong results...

Anyway, here is my solution that is quite efficient and simple and works for all cases. The trick is just to find the previous Monday for start and end dates, and then do a small compensation when start and end happens during the weekend:

public double WorkDays(DateTime startDate, DateTime endDate){
        double weekendDays;

        double days = endDate.Subtract(startDate).TotalDays;

        if(days<0) return 0;

        DateTime startMonday = startDate.AddDays(DayOfWeek.Monday - startDate.DayOfWeek).Date;
        DateTime endMonday = endDate.AddDays(DayOfWeek.Monday - endDate.DayOfWeek).Date;

        weekendDays = ((endMonday.Subtract(startMonday).TotalDays) / 7) * 2;

        // compute fractionary part of weekend days
        double diffStart = startDate.Subtract(startMonday).TotalDays - 5;
        double diffEnd = endDate.Subtract(endMonday).TotalDays - 5;

        // compensate weekenddays
        if(diffStart>0) weekendDays -= diffStart;
        if(diffEnd>0) weekendDays += diffEnd;

        return days - weekendDays;
    }
Superfuse answered 21/8, 2012 at 7:45 Comment(1)
This returns -1 if called with a Saturday and Sunday.Verret
B
1
using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            DateTime start = new DateTime(2014, 1, 1);
            DateTime stop = new DateTime(2014, 12, 31);

            int totalWorkingDays = GetNumberOfWorkingDays(start, stop);

            Console.WriteLine("There are {0} working days.", totalWorkingDays);
        }

        private static int GetNumberOfWorkingDays(DateTime start, DateTime stop)
        {
            TimeSpan interval = stop - start;

            int totalWeek = interval.Days / 7;
            int totalWorkingDays = 5 * totalWeek;

            int remainingDays = interval.Days % 7;


            for (int i = 0; i <= remainingDays; i++)
            {
                DayOfWeek test = (DayOfWeek)(((int)start.DayOfWeek + i) % 7);
                if (test >= DayOfWeek.Monday && test <= DayOfWeek.Friday)
                    totalWorkingDays++;
            }

            return totalWorkingDays;
        }
    }
}
Brimful answered 12/10, 2014 at 18:32 Comment(0)
T
1

Here is the function which we can use to calculate business days between two date. I'm not using holiday list as it can vary accross country/region.

If we want to use it anyway we can take third argument as list of holiday and before incrementing count we should check that list does not contains d

public static int GetBussinessDaysBetweenTwoDates(DateTime StartDate,   DateTime EndDate)
    {
        if (StartDate > EndDate)
            return -1;

        int bd = 0;

        for (DateTime d = StartDate; d < EndDate; d = d.AddDays(1))
        {
            if (d.DayOfWeek != DayOfWeek.Saturday && d.DayOfWeek != DayOfWeek.Sunday)
                bd++;
        }

        return bd;
    }
Truism answered 2/3, 2016 at 9:40 Comment(0)
F
1

By using marinjw library, And solution provided by Alec Pojidaev i created below, this will skip public (you need to specify country) holidays:

Please Note that if you use actual DateTime and have hours present then you have to add .Date and best to reformat FromDate and ToDate as FromDate = FromDate.Date and ToDate = ToDate.Date

public static int GetProcessingTime(this DateTime? FromDate, DateTime? ToDate)
{
    if (FromDate == null) return 0;
    if (ToDate == null) return 0;

    List<DateTime> Holidays = new List<DateTime>();

    int startyear = FromDate.Value.Year;
    int endyear = ToDate.Value.Year;

    //loop years to extract all holidays
    for(int i = startyear; i <= endyear; i++)
    {
        IList<DateTime> Temp = new PolandPublicHoliday().PublicHolidays(i);
        Holidays.AddRange(Temp.ToList());
    }

    //exclude holidays outside of range
    Holidays = Holidays.Where(x => x >= FromDate && x <= ToDate).ToList();

    //exclude holidays that are set to be on sunday/saturday
    Holidays = Holidays.Where(x => x.DayOfWeek != DayOfWeek.Sunday && x.DayOfWeek != DayOfWeek.Saturday).ToList();

    //calculate date difference without sundays and saturdays Value need to be added as I am using nullable DateTime
    double calcBusinessDays = 1 + ((FromDate.Value - ToDate.Value).TotalDays * 5 - (FromDate.Value.DayOfWeek - ToDate.Value.DayOfWeek) * 2) / 7;

    if (FromDate.Value.DayOfWeek == DayOfWeek.Saturday) calcBusinessDays--;
    if (ToDate.Value.DayOfWeek == DayOfWeek.Sunday) calcBusinessDays--;

    //remove left holidays
    if (Holidays!=null)
        calcBusinessDays -= Holidays.Count;

    return (int)calcBusinessDays;
}
Fernando answered 13/7, 2022 at 12:41 Comment(0)
B
0

I'll just share my solution. It worked for me, maybe I just don't notice/know that theres a bug. I started by getting the first incomplete week if there's any. a complete week was from sunday for saturday, so if the (int)_now.DayOfWeek was not 0(Sunday), the first week was incomplete.

I just subtract 1 to first weeks count for the first week's saturday then add it to new count;

Then I get the last incomplete week, then subtract 1 for it's sunday then add to new count.

Then finally, the number of complete weeks multiply by 5(weekdays) was added to new count.

public int RemoveNonWorkingDays(int numberOfDays){

            int workingDays = 0;

            int firstWeek = 7 - (int)_now.DayOfWeek;

            if(firstWeek < 7){

                if(firstWeek > numberOfDays)
                    return numberOfDays;

                workingDays += firstWeek-1;
                numberOfDays -= firstWeek;
            }


            int lastWeek = numberOfDays % 7;

            if(lastWeek > 0){

                numberOfDays -= lastWeek;
                workingDays += lastWeek - 1;

            }

            workingDays += (numberOfDays/7)*5;

            return workingDays;
        }
Briones answered 5/4, 2013 at 8:20 Comment(0)
A
0

I was having trouble finding a solid TSQL version of this code. Below is essentially a conversion of the C# code here with addition of the Holiday table which should be used to pre-calculate holidays.

CREATE TABLE dbo.Holiday
(
    HolidayDt       DATE NOT NULL,
    Name            NVARCHAR(50) NOT NULL,
    IsWeekday       BIT NOT NULL,
    CONSTRAINT PK_Holiday PRIMARY KEY (HolidayDt)
)
GO
CREATE INDEX IDX_Holiday ON Holiday (HolidayDt, IsWeekday)

GO

CREATE function dbo.GetBusinessDays
(
     @FirstDay  datetime,
     @LastDay   datetime
) 
RETURNS INT
 AS
BEGIN
    DECLARE @BusinessDays INT, @FullWeekCount INT 
    SELECT  @FirstDay = CONVERT(DATETIME,CONVERT(DATE,@FirstDay))
        ,   @LastDay = CONVERT(DATETIME,CONVERT(DATE,@LastDay))

    IF @FirstDay > @LastDay
        RETURN NULL;

    SELECT @BusinessDays = DATEDIFF(DAY, @FirstDay, @LastDay) + 1 
    SELECT @FullWeekCount = @BusinessDays / 7;

    -- find out if there are weekends during the time exceedng the full weeks
    IF @BusinessDays > (@FullWeekCount * 7)
    BEGIN
    -- we are here to find out if there is a 1-day or 2-days weekend
    -- in the time interval remaining after subtracting the complete weeks
        DECLARE @firstDayOfWeek INT, @lastDayOfWeek INT;
        SELECT @firstDayOfWeek = DATEPART(DW, @FirstDay), @lastDayOfWeek = DATEPART(DW, @LastDay);

        IF @lastDayOfWeek < @firstDayOfWeek
                SELECT @lastDayOfWeek = @lastDayOfWeek + 7;

        IF @firstDayOfWeek <= 6 
            BEGIN
                IF (@lastDayOfWeek >= 7) --Both Saturday and Sunday are in the remaining time interval
                    BEGIN 
                        SELECT @BusinessDays = @BusinessDays - 2
                    END
                ELSE IF @lastDayOfWeek>=6 --Only Saturday is in the remaining time interval
                    BEGIN
                        SELECT @BusinessDays = @BusinessDays - 1
                    END

            END
        ELSE IF @firstDayOfWeek <= 7 AND @lastDayOfWeek >=7 -- Only Sunday is in the remaining time interval
        BEGIN 
            SELECT @BusinessDays = @BusinessDays - 1
        END
    END

    -- subtract the weekends during the full weeks in the interval
    DECLARE @Holidays INT;
    SELECT  @Holidays = COUNT(*) 
    FROM    Holiday 
    WHERE   HolidayDt BETWEEN @FirstDay AND @LastDay 
    AND     IsWeekday = CAST(1 AS BIT)

    SELECT @BusinessDays = @BusinessDays - (@FullWeekCount + @FullWeekCount) -- - @Holidays

    RETURN @BusinessDays
END
Arther answered 27/11, 2013 at 16:8 Comment(0)
L
0
    int BusinessDayDifference(DateTime Date1, DateTime Date2)
    {
        int Sign = 1;
        if (Date2 > Date1)
        {
            Sign = -1;
            DateTime TempDate = Date1;
            Date1 = Date2;
            Date2 = TempDate;
        }
        int BusDayDiff = (int)(Date1.Date - Date2.Date).TotalDays;
        if (Date1.DayOfWeek == DayOfWeek.Saturday)
            BusDayDiff -= 1;
        if (Date2.DayOfWeek == DayOfWeek.Sunday)
            BusDayDiff -= 1;
        int Week1 = GetWeekNum(Date1);
        int Week2 = GetWeekNum(Date2);
        int WeekDiff = Week1 - Week2;
        BusDayDiff -= WeekDiff * 2;
        foreach (DateTime Holiday in Holidays)
            if (Date1 >= Holiday && Date2 <= Holiday)
                BusDayDiff--;
        BusDayDiff *= Sign;
        return BusDayDiff;
    }

    private int GetWeekNum(DateTime Date)
    {
        return (int)(Date.AddDays(-(int)Date.DayOfWeek).Ticks / TimeSpan.TicksPerDay / 7);
    }
Lodging answered 12/5, 2014 at 15:28 Comment(0)
K
0

Here is one very simple solution for this problem. We have starting date, end date and "for loop" for encreasing the day and calculating to see if it's a workday or a weekend by converting to string DayOfWeek.

class Program
{
    static void Main(string[] args)
    {
        DateTime day = new DateTime();
        Console.Write("Inser your end date (example: 01/30/2015): ");
        DateTime endDate = DateTime.Parse(Console.ReadLine());
        int numberOfDays = 0;
        for (day = DateTime.Now.Date; day.Date < endDate.Date; day = day.Date.AddDays(1))
        {
            string dayToString = Convert.ToString(day.DayOfWeek);
            if (dayToString != "Saturday" && dayToString != "Sunday") numberOfDays++;
        }
        Console.WriteLine("Number of working days (not including local holidays) between two dates is "+numberOfDays);
    }
}
Karleen answered 24/5, 2014 at 9:53 Comment(0)
C
0

Based on the comment marked as answer and patch recommended , as well as -> This version wants to convert the Days to Business-Hours ... Considers Same day hours as well.

 /// <summary>
    /// Calculates number of business days, taking into account:
    ///  - weekends (Saturdays and Sundays)
    ///  - bank holidays in the middle of the week
    /// </summary>
    /// <param name="firstDay">First day in the time interval</param>
    /// <param name="lastDay">Last day in the time interval</param>
    /// <param name="bankHolidays">List of bank holidays excluding weekends</param>
    /// <returns>Number of business hours during the 'span'</returns>
    public static int BusinessHoursUntil(DateTime firstDay, DateTime lastDay, params DateTime[] bankHolidays)
    {
        var original_firstDay = firstDay;
        var original_lastDay = lastDay;
        firstDay = firstDay.Date;
        lastDay = lastDay.Date;
        if (firstDay > lastDay)
            return -1; //// throw new ArgumentException("Incorrect last day " + lastDay);

        TimeSpan span = lastDay - firstDay;
        int businessDays = span.Days + 1;
        int fullWeekCount = businessDays / 7;
        // find out if there are weekends during the time exceedng the full weeks
        if (businessDays > fullWeekCount * 7)
        {
            // we are here to find out if there is a 1-day or 2-days weekend
            // in the time interval remaining after subtracting the complete weeks
            int firstDayOfWeek = firstDay.DayOfWeek == DayOfWeek.Sunday ? 7 : (int)firstDay.DayOfWeek;
            int lastDayOfWeek = lastDay.DayOfWeek == DayOfWeek.Sunday ? 7 : (int)lastDay.DayOfWeek;

            if (lastDayOfWeek < firstDayOfWeek)
                lastDayOfWeek += 7;
            if (firstDayOfWeek <= 6)
            {
                if (lastDayOfWeek >= 7)// Both Saturday and Sunday are in the remaining time interval
                    businessDays -= 2;
                else if (lastDayOfWeek >= 6)// Only Saturday is in the remaining time interval
                    businessDays -= 1;
            }
            else if (firstDayOfWeek <= 7 && lastDayOfWeek >= 7)// Only Sunday is in the remaining time interval
                businessDays -= 1;
        }

        // subtract the weekends during the full weeks in the interval
        businessDays -= fullWeekCount + fullWeekCount;

        if (bankHolidays != null && bankHolidays.Any())
        {
            // subtract the number of bank holidays during the time interval
            foreach (DateTime bankHoliday in bankHolidays)
            {
                DateTime bh = bankHoliday.Date;
                if (firstDay <= bh && bh <= lastDay)
                    --businessDays;
            }
        }

        int total_business_hours = 0;
        if (firstDay.Date == lastDay.Date)
        {//If on the same day, go granular with Hours from the Orginial_*Day values
            total_business_hours = (int)(original_lastDay - original_firstDay).TotalHours;
        }
        else
        {//Convert Business-Days to TotalHours
            total_business_hours = (int)(firstDay.AddDays(businessDays).AddHours(firstDay.Hour) - firstDay).TotalHours;
        }
        return total_business_hours;
    }
Caravansary answered 2/7, 2014 at 14:22 Comment(0)
W
0

I just improved @Alexander and @Slauma answer to support a business week as a parameter, for cases where saturday is a business day, or even cases where there is just a couple of days of the week that are considered business days:

/// <summary>
/// Calculate the number of business days between two dates, considering:
///  - Days of the week that are not considered business days.
///  - Holidays between these two dates.
/// </summary>
/// <param name="fDay">First day of the desired 'span'.</param>
/// <param name="lDay">Last day of the desired 'span'.</param>
/// <param name="BusinessDaysOfWeek">Days of the week that are considered to be business days, if NULL considers monday, tuesday, wednesday, thursday and friday as business days of the week.</param>
/// <param name="Holidays">Holidays, if NULL, considers no holiday.</param>
/// <returns>Number of business days during the 'span'</returns>
public static int BusinessDaysUntil(this DateTime fDay, DateTime lDay, DayOfWeek[] BusinessDaysOfWeek = null, DateTime[] Holidays = null)
{
    if (BusinessDaysOfWeek == null)
        BusinessDaysOfWeek = new DayOfWeek[] { DayOfWeek.Monday, DayOfWeek.Tuesday, DayOfWeek.Wednesday, DayOfWeek.Thursday, DayOfWeek.Friday };
    if (Holidays == null)
        Holidays = new DateTime[] { };

    fDay = fDay.Date;
    lDay = lDay.Date;

    if (fDay > lDay)
        throw new ArgumentException("Incorrect last day " + lDay);

    int bDays = (lDay - fDay).Days + 1;
    int fullWeekCount = bDays / 7;
    int fullWeekCountMult = 7 - WeekDays.Length;
    //  Find out if there are weekends during the time exceedng the full weeks
    if (bDays > (fullWeekCount * 7))
    {
        int fDayOfWeek = (int)fDay.DayOfWeek;
        int lDayOfWeek = (int)lDay.DayOfWeek;

        if (fDayOfWeek > lDayOfWeek)
            lDayOfWeek += 7;

        // If they are the same, we already covered it right before the Holiday subtraction
        if (lDayOfWeek != fDayOfWeek)
        {
            //  Here we need to see if any of the days between are considered business days
            for (int i = fDayOfWeek; i <= lDayOfWeek; i++)
                if (!WeekDays.Contains((DayOfWeek)(i > 6 ? i - 7 : i)))
                    bDays -= 1;
        }
    }

    //  Subtract the days that are not in WeekDays[] during the full weeks in the interval
    bDays -= (fullWeekCount * fullWeekCountMult);
    //  Subtract the number of bank holidays during the time interval
    bDays = bDays - Holidays.Select(x => x.Date).Count(x => fDay <= x && x <= lDay);

    return bDays;
}
Wernick answered 16/1, 2015 at 13:24 Comment(0)
F
0

I believe this could be a simpler way:

    public int BusinessDaysUntil(DateTime start, DateTime end, params DateTime[] bankHolidays)
    {
        int tld = (int)((end - start).TotalDays) + 1; //including end day
        int not_buss_day = 2 * (tld / 7); //Saturday and Sunday
        int rest = tld % 7; //rest.

        if (rest > 0)
        {
            int tmp = (int)start.DayOfWeek - 1 + rest;
            if (tmp == 6 || start.DayOfWeek == DayOfWeek.Sunday) not_buss_day++; else if (tmp > 6) not_buss_day += 2;
        }

        foreach (DateTime bankHoliday in bankHolidays)
        {
            DateTime bh = bankHoliday.Date;
            if (!(bh.DayOfWeek == DayOfWeek.Saturday || bh.DayOfWeek == DayOfWeek.Sunday) && (start <= bh && bh <= end))
            {
                not_buss_day++;
            }
        }
        return tld - not_buss_day;
    }
Flocky answered 3/6, 2016 at 13:45 Comment(0)
C
0

Here's yet another idea - this method allows to specify any working week and holidays.

The idea here is that we find the core of the date range from the first first working day of the week to the last weekend day of the week. This enables us to calculate the whole weeks easily (without iterating over all of the dates). All we need to do then is to add the working days that fall before the start and end of this core range.

public static int CalculateWorkingDays(
    DateTime startDate, 
    DateTime endDate, 
    IList<DateTime> holidays, 
    DayOfWeek firstDayOfWeek,
    DayOfWeek lastDayOfWeek)
{
    // Make sure the defined working days run contiguously
    if (lastDayOfWeek < firstDayOfWeek)
    {
        throw new Exception("Last day of week cannot fall before first day of week!");
    }

    // Create a list of the days of the week that make-up the weekend by working back
    // from the firstDayOfWeek and forward from lastDayOfWeek to get the start and end
    // the weekend
    var weekendStart = lastDayOfWeek == DayOfWeek.Saturday ? DayOfWeek.Sunday : lastDayOfWeek + 1;
    var weekendEnd = firstDayOfWeek == DayOfWeek.Sunday ? DayOfWeek.Saturday : firstDayOfWeek - 1;
    var weekendDays = new List<DayOfWeek>();

    var w = weekendStart;
    do {
        weekendDays.Add(w);
        if (w == weekendEnd) break;
        w = (w == DayOfWeek.Saturday) ? DayOfWeek.Sunday : w + 1;
    } while (true);


    // Force simple dates - no time
    startDate = startDate.Date;
    endDate = endDate.Date;

    // Ensure a progessive date range
    if (endDate < startDate)
    {
        var t = startDate;
        startDate = endDate;
        endDate = t;
    }

    // setup some working variables and constants
    const int daysInWeek = 7;           // yeah - really!
    var actualStartDate = startDate;    // this will end up on startOfWeek boundary
    var actualEndDate = endDate;        // this will end up on weekendEnd boundary
    int workingDaysInWeek = daysInWeek - weekendDays.Count;

    int workingDays = 0;        // the result we are trying to find
    int leadingDays = 0;        // the number of working days leading up to the firstDayOfWeek boundary
    int trailingDays = 0;       // the number of working days counting back to the weekendEnd boundary

    // Calculate leading working days
    // if we aren't on the firstDayOfWeek we need to step forward to the nearest
    if (startDate.DayOfWeek != firstDayOfWeek)
    {
        var d = startDate;
        do {
            if (d.DayOfWeek == firstDayOfWeek || d >= endDate)
            {
                actualStartDate = d;
                break;  
            }
            if (!weekendDays.Contains(d.DayOfWeek))
            {
                leadingDays++;
            }
            d = d.AddDays(1);
        } while(true);
    }

    // Calculate trailing working days
    // if we aren't on the weekendEnd we step back to the nearest
    if (endDate >= actualStartDate && endDate.DayOfWeek != weekendEnd)
    {
        var d = endDate;
        do {
            if (d.DayOfWeek == weekendEnd || d < actualStartDate)
            {
                actualEndDate = d;
                break;  
            }
            if (!weekendDays.Contains(d.DayOfWeek))
            {
                trailingDays++;
            }
            d = d.AddDays(-1);
        } while(true);
    }

    // Calculate the inclusive number of days between the actualStartDate and the actualEndDate
    var coreDays = (actualEndDate - actualStartDate).Days + 1;
    var noWeeks =  coreDays / daysInWeek;

    // add together leading, core and trailing days
    workingDays +=  noWeeks * workingDaysInWeek;
    workingDays += leadingDays;
    workingDays += trailingDays;

    // Finally remove any holidays that fall within the range.
    if (holidays != null)
    {
        workingDays -= holidays.Count(h => h >= startDate && (h <= endDate));
    }

    return workingDays;
}
Cuprite answered 11/1, 2017 at 13:2 Comment(0)
M
0

Since I can't comment. There is one more issue with the accepted solution where bank holidays are subtracted even when they are situated in the weekend. Seeing how other input is checked, it is only fitting that this is as well.

The foreach should therefore be:

    // subtract the number of bank holidays during the time interval
    foreach (DateTime bankHoliday in bankHolidays)
    {
        DateTime bh = bankHoliday.Date;

        // Do not subtract bank holidays when they fall in the weekend to avoid double subtraction
        if (bh.DayOfWeek == DayOfWeek.Saturday || bh.DayOfWeek == DayOfWeek.Sunday)
                continue;

        if (firstDay <= bh && bh <= lastDay)
            --businessDays;
    }
Morville answered 30/8, 2017 at 13:4 Comment(0)
L
0

Here is an approach if you are using MVC. I have also calculated national holidays or any festive days to be excluded by fetching it from holidayscalendar which you will need to make one.

        foreach (DateTime day in EachDay(model))
        {
            bool key = false;
            foreach (LeaveModel ln in holidaycalendar)
            {
                if (day.Date == ln.Date && day.DayOfWeek != DayOfWeek.Saturday && day.DayOfWeek != DayOfWeek.Sunday)
                {
                    key = true; break;
                }
            }
            if (day.DayOfWeek == DayOfWeek.Saturday || day.DayOfWeek == DayOfWeek.Sunday)
            {
                key = true;
            }
            if (key != true)
            {
                leavecount++;
            }
        }

Leavemodel is a list here

Lysias answered 15/5, 2018 at 19:50 Comment(0)
H
0

Here is an helper function I wrote for that task.
it also returns the count of weekends via the out parameter.
if you wish you can customize the "weekend" days in run time for countries that use different weekend days or to include holidays trough the weekendDays[] optional parameter :

public static int GetNetworkDays(DateTime startDate, DateTime endDate,out int totalWeekenDays, DayOfWeek[] weekendDays = null)
{
    if (startDate >= endDate)
    {
        throw new Exception("start date can not be greater then or equel to end date");
    }

    DayOfWeek[] weekends = new DayOfWeek[] { DayOfWeek.Sunday, DayOfWeek.Saturday };
    if (weekendDays != null)
    {
        weekends = weekendDays;
    }

    int totaldays = (int)Math.Round((endDate - startDate).TotalDays) + 1; // add one to include the first day too
    var counter = 0;
    var workdaysCounter = 0;
    var weekendsCounter = 0;

    for (int i = 0; i < totaldays; i++)
    {

        if (weekends.Contains(startDate.AddDays(counter).DayOfWeek))
        {
            weekendsCounter++;
        }
        else
        {
            workdaysCounter++;
        }

        counter++;
    }

    totalWeekenDays = weekendsCounter;
    return workdaysCounter;
}
Hols answered 7/1, 2019 at 12:44 Comment(0)
D
0

I came up with the following solution

var dateStart = new DateTime(2019,01,10);
var dateEnd = new DateTime(2019,01,31);

var timeBetween = (dateEnd - dateStart).TotalDays + 1;
int numberOf7DayWeeks = (int)(timeBetween / 7);
int numberOfWeekendDays = numberOf7DayWeeks * 2;
int workingDays =(int)( timeBetween - numberOfWeekendDays);

if(dateStart.DayOfWeek == DayOfWeek.Saturday || dateEnd.DayOfWeek == DayOfWeek.Sunday){
    workingDays -=2;
}       
if(dateStart.DayOfWeek == DayOfWeek.Sunday || dateEnd.DayOfWeek == DayOfWeek.Saturday){
    workingDays -=1;
}
Daina answered 17/4, 2019 at 15:47 Comment(0)
R
0

You just have to iterate through each day in the time range and subtract a day from the counter if its a Saturday or a Sunday.

    private float SubtractWeekend(DateTime start, DateTime end) {
        float totaldays = (end.Date - start.Date).Days;
        var iterationVal = totalDays;
        for (int i = 0; i <= iterationVal; i++) {
            int dayVal = (int)start.Date.AddDays(i).DayOfWeek;
            if(dayVal == 6 || dayVal == 0) {
                // saturday or sunday
                totalDays--;
            }
        }
        return totalDays;
    }
Radiosurgery answered 14/6, 2019 at 14:14 Comment(0)
B
0

Yet another approach for calculating business days, not considering holidays, but taking into account the time of day returning a fractional amount of days:

public static double GetBusinessDays(DateTime startD, DateTime endD)
{
    while (IsWeekend(startD))
        startD = startD.Date.AddDays(1);

    while (IsWeekend(endD))
        endD = endD.Date.AddDays(-1);

    var bussDays = (endD - startD).TotalDays -
        (2 * ((int)(endD - startD).TotalDays / 7)) -
        (startD.DayOfWeek > endD.DayOfWeek ? 2 : 0);

    return bussDays;
}

public static bool IsWeekend(DateTime d)
{
    return d.DayOfWeek == DayOfWeek.Saturday || d.DayOfWeek == DayOfWeek.Sunday;
}

You can fiddle with it here: https://rextester.com/ASHRS53997

Burmaburman answered 17/10, 2019 at 13:0 Comment(0)
N
0
public static int CalculateBusinessDaysInRange(this DateTime startDate, DateTime endDate, params DateTime[] holidayDates)
{
    endDate = endDate.Date;
    if(startDate > endDate)
        throw new ArgumentException("The end date can not be before the start date!", nameof(endDate));
    int accumulator = 0;
    DateTime itterator = startDate.Date;
    do 
    {
        if(itterator.DayOfWeek != DayOfWeek.Saturday && itterator.DayOfWeek != DayOfWeek.Sunday && !holidayDates.Any(hol => hol.Date == itterator))
        { accumulator++; }
    } 
    while((itterator = itterator.AddDays(1)).Date <= endDate);
    return accumulator
}

I'm only posting this because despite all of the excellent answers that have been given, none of the math made sense to me. This is definitely a KISS method that should work and be fairly maintainable. Granted if you are calculating ranges that are greater than 2-3 months this will not be the most effective way. We simply determine if it is a Saturday or Sunday or the date is a given holiday date. If it's not we add a business day. If it is then everything is fine.

I'm sure this could be even more so simplified with LINQ, but this way is much easier to understand.

Nide answered 21/10, 2019 at 14:41 Comment(0)
S
0

Here's another example you can choose the weekend dates as well,

  public int GetBuisnessDays(DateTime StartDate, DateTime EndDate)
    {
        int counter = 0;

        if (StartDate.Date == EndDate.Date)
        {
            if (StartDate.DayOfWeek != DayOfWeek.Saturday && StartDate.DayOfWeek != DayOfWeek.Friday)
                return 1;
            return 0;
        }

        while (StartDate <= EndDate)
        {
            if (StartDate.DayOfWeek != DayOfWeek.Saturday && StartDate.DayOfWeek != DayOfWeek.Friday)
                ++counter;
            StartDate = StartDate.AddDays(1);
        }

        return counter;
    }
Swathe answered 27/12, 2020 at 10:9 Comment(0)
C
0

So I had a similar task except I had to calculate business days left (from date should not be more than to date), and end date should skip to next business day.

To make it more understandable/readable, I did this in the following steps

  1. Updated toDate to the next business day if it is on weekend.

  2. Find out the number of complete weeks between dates, and for each complete week consider 5 days in running total.

  3. Now days left are only different of from and to weekdays (it won't be more than 6 days), so wrote a small loop to get it (skip Saturday and Sunday)

     public static int GetBusinessDaysLeft(DateTime fromDate, DateTime toDate)
     {
         //Validate that startDate should be less than endDate
         if (fromDate >= toDate) return 0;
    
         //Move end date to Monday if on weekends
         if (toDate.DayOfWeek == DayOfWeek.Saturday || toDate.DayOfWeek == DayOfWeek.Sunday)
             while (toDate.DayOfWeek != DayOfWeek.Monday)
                 toDate = toDate.AddDays(+1);
    
         //Consider 5 days per complete week in between start and end dates
         int remainder, quotient = Math.DivRem((toDate - fromDate).Days, 7, out remainder);
         var daysDiff = quotient * 5;
    
         var curDay = fromDate;
         while (curDay.DayOfWeek != toDate.DayOfWeek)
         {
             curDay = curDay.AddDays(1);
             if (curDay.DayOfWeek == DayOfWeek.Saturday || curDay.DayOfWeek == DayOfWeek.Sunday)
                 continue;
    
             daysDiff += 1;
         }
         return daysDiff;
     }
    
Cockatiel answered 15/2, 2021 at 16:58 Comment(0)
I
0

Many of the answers are great but they don't take into account the start/end time. Here is my improved solutions (in C#) based on this answers but taking into account the start and end time. For example:

  • Monday 8/2/2021 to Wednesday 8/4/2021 is 2 days - In this case, 8/4/2021 is excluded because the time is not specified and in .Net it automatically assigned to 12:00 AM.

  • Monday 8/2/2021 12 PM to Wednesday 8/4/2021 12 PM is 2 days.

  • Friday 8/6/2021 12 PM to Tuesday 8/10/2021 6 PM is 2.25 days.

    public static double GetWorkingDays(DateTime startDate, DateTime endDate)
    {
      // Get next full day from start date and last full day of end date
      var nextFullStartDate = startDate.AddDays(1).Date;
      var lastFullEndDate = endDate.Date;
    
      // Calculate total days based on start and end's day of week
      var dayOfWeekFactor = (nextFullStartDate.DayOfWeek - lastFullEndDate.DayOfWeek) * 2;
      if (lastFullEndDate.DayOfWeek == DayOfWeek.Sunday)
      {
          // In .net, day of week for Sunday is 0, we need to change it to 7
          dayOfWeekFactor = ((int)nextFullStartDate.DayOfWeek - 7) * 2;
      }
    
      // Calculate working days (ie: Monday, Tuesday, Wednesday, Thursday and Friday)
      var workingDayCount = ((lastFullEndDate - nextFullStartDate).TotalDays * 5 - dayOfWeekFactor) / 7;
    
      // Subtract working days if full start date or last full end date is Sunday
      // Saturday is not included here because if startDate is Saturday the formula above would have excluded Saturday. If the endDate is Saturday, it would have been excluded too because the time would be Saturday 12:00 AM
      if (nextFullStartDate.DayOfWeek == DayOfWeek.Sunday || lastFullEndDate.DayOfWeek == DayOfWeek.Sunday)
      {
           workingDayCount--;
      }
    
      // Count the real start/end date
      if (startDate.DayOfWeek != DayOfWeek.Saturday &&
          startDate.DayOfWeek != DayOfWeek.Sunday)
      {
          var startDateFraction = (nextFullStartDate - startDate).TotalHours / 24;
          workingDayCount += startDateFraction;
      }
    
      if (endDate.DayOfWeek != DayOfWeek.Saturday &&
        endDate.DayOfWeek != DayOfWeek.Sunday)
      {
          var endDateFraction = (endDate - lastFullEndDate).TotalHours / 24;
          workingDayCount += endDateFraction;
      }
    
      return workingDayCount;
    }
    
Incomprehensible answered 23/9, 2021 at 21:41 Comment(0)
C
0

  <!--  **Here is the solution for getting working days except for all Sundays and 2nd-4th Saturdays**-->

public void GetWorkingDays
        {
            DateTime from = new DateTime(2022, 10, 03, 10, 30, 50);
            DateTime to = new DateTime(2022, 11, 15, 16, 30, 50);
            
            Console.WriteLine("From: "+from);
            Console.WriteLine("To: "+to);
            Program pgm = new Program();
            List<DateTime> allDates1 = pgm.GetDatesBetween(from, to);     
  <!--  //here this above list will print all working days except for all Sundays and 2nd-4th Saturdays -->
        }

      <!--  //get List of Between dates-->
        public List<DateTime> GetDatesBetween(DateTime startDate, DateTime endDate)
        {
            List<DateTime> allDates = new List<DateTime>();
            List<DateTime> Saturday = GetSaturdayDatesBetween(startDate, endDate);
            for (DateTime date = startDate; date <= endDate; date = date.AddDays(1))
                if (date.DayOfWeek != DayOfWeek.Sunday && !Saturday.Contains(date.Date))
                {
                    if (date.Date != endDate.Date)
                    {
                        allDates.Add(date);
                    }
                    else
                    {
                        allDates.Add(endDate);
                    }
                }
            return allDates;

        }

       <!-- //Get 2nd and 3rd Saturday -->
        public List<DateTime> GetSaturdayDatesBetween(DateTime from, DateTime to)
        {
            List<DateTime> Saturday = new List<DateTime>();

            for (DateTime date = from; date <= to; date = date.AddMonths(1))
            {
                var start = new DateTime(from.Year, date.Month, 1, from.Hour, from.Minute, from.Second, from.Millisecond);
                var end = DateTime.DaysInMonth(from.Year, date.Month);
                var endDate = new DateTime(date.Year, date.Month, end,  date.Hour, date.Minute, date.Second, date.Millisecond);
                int satCount=0;
                for (DateTime curDate = start; curDate <= endDate; curDate = curDate.AddDays(1))
                {
                    if(curDate.DayOfWeek == DayOfWeek.Saturday)
                    {
                        satCount++;
                        if (satCount == 2 || satCount == 4)
                        {
                            Saturday.Add(curDate.Date);
                        }

                    }
                }
            }
            return Saturday;
        }
Conscience answered 21/11, 2022 at 7:16 Comment(0)
F
0

Try this, No iteration through all the days! Worked well so far:

  private int CalculateDateDifference(DateTime startdate, DateTime endDate)
    {
        int businessDays = (endDate - startdate).Days;
        var weekendCount = 0;

        if (businessDays > 6)
        {
            weekendCount += 2;
            startdate = startdate.AddDays(7);
            while (startdate <= endDate)
            {
                startdate = startdate.AddDays(7);
                if (startdate <= endDate || ( (int)endDate.DayOfWeek < (int)startdate.DayOfWeek && endDate.DayOfWeek!=DayOfWeek.Sunday))
                    weekendCount += 2;
            }
           
        }
        else if ((int)endDate.DayOfWeek < (int)startdate.DayOfWeek)
        {
            weekendCount += 2;
        }

        //Exclude weekends
        businessDays = businessDays - weekendCount;

        //Check if Last day was on Weekend
        if (endDate.DayOfWeek == DayOfWeek.Saturday) businessDays -= 1;
        if (endDate.DayOfWeek == DayOfWeek.Sunday) businessDays -= 2;


        return businessDays;

    }

Note: This solution assumes startDate is on a Week day. Can be tweaked to handled Weekend start day as well.

Frierson answered 25/1, 2023 at 10:12 Comment(1)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Langston
H
0
public static int CalculateWorkDays(DateTime startDate, DateTime endDate)
    {
        //Step0: remove hours, minutes, seconds of startDate and endDate.
        startDate = new DateTime(startDate.Year, startDate.Month, [![enter image description here][1]][1]startDate.Day);
        endDate = new DateTime(endDate.Year, endDate.Month, endDate.Day);
        //Step1: fill days to whole weeks. ps.Sunday is the first day, and its DayOfWeek is 0.
        int wholeWeekDays = (endDate - startDate).Days + ((int)startDate.DayOfWeek + 1) + (6 - (int)endDate.DayOfWeek);
        //Step2: calculate work days of the whole weeks
        int filledWorkDays = wholeWeekDays / 7 * 5;
        //Step3: minus prefilled work days
        int filledWorkDaysForStartDate = startDate.DayOfWeek == DayOfWeek.Sunday ? 0 : (int)startDate.DayOfWeek - 1; //Sunday should be excluded, because it's not a work day
        int filledWorkDaysForEndDate = endDate.DayOfWeek == DayOfWeek.Sunday ? 5 : 6 - (int)endDate.DayOfWeek;
        int workDays = filledWorkDays - filledWorkDaysForStartDate - filledWorkDaysForEndDate;
        return workDays;
    }

EndDate: 9th March, 2023
Test Cases is attached below:
enter image description here

Howells answered 9/3, 2023 at 13:2 Comment(0)
I
0
    public static int BusinessDays(this DateTime firstDay, DateTime lastDay)
    {
        firstDay = firstDay.Date;
        lastDay = lastDay.Date;

        if (firstDay > lastDay)
        {
            var dDay = firstDay;
            firstDay = lastDay;
            lastDay = dDay;
        }
        int dateDiff = (lastDay - firstDay).Days;
        int weekCount = (dateDiff + (int)firstDay.DayOfWeek) / 7;
        return dateDiff - weekCount * 2 + ((int)lastDay.DayOfWeek == 6 || (int)firstDay.DayOfWeek == 0 ? 1 : 0);
    }
Ignite answered 2/5 at 10:10 Comment(0)
B
-1

This is a generic solution.

startdayvalue is day number of start date.

weekendday_1 is day numner of week end.

day number - MON - 1, TUE - 2, ... SAT - 6, SUN -7.

difference is difference between two dates..

Example : Start Date : 4 April, 2013, End Date : 14 April, 2013

Difference : 10, startdayvalue : 4, weekendday_1 : 7 (if SUNDAY is a weekend for you.)

This will give you number of holidays.

No of business day = (Difference + 1) - holiday1

    if (startdayvalue > weekendday_1)
    {

        if (difference > ((7 - startdayvalue) + weekendday_1))
        {
            holiday1 = (difference - ((7 - startdayvalue) + weekendday_1)) / 7;
            holiday1 = holiday1 + 1;
        }
        else
        {
            holiday1 = 0;
        }
    }
    else if (startdayvalue < weekendday_1)
    {

        if (difference > (weekendday_1 - startdayvalue))
        {
            holiday1 = (difference - (weekendday_1 - startdayvalue)) / 7;
            holiday1 = holiday1 + 1;
        }
        else if (difference == (weekendday_1 - startdayvalue))
        {
            holiday1 = 1;
        }
        else
        {
            holiday1 = 0;
        }
    }
    else
    {
        holiday1 = difference / 7;
        holiday1 = holiday1 + 1;
    }
Bryonbryony answered 26/4, 2013 at 9:11 Comment(0)
R
-1
 public enum NonWorkingDays { SaturdaySunday = 0, FridaySaturday = 1 };
        public int getBusinessDates(DateTime dateSt, DateTime dateNd, NonWorkingDays nonWorkingDays = NonWorkingDays.SaturdaySunday)
        {
            List<DateTime> datelist = new List<DateTime>();
            while (dateSt.Date < dateNd.Date)
            {
                datelist.Add((dateSt = dateSt.AddDays(1)));
            }
            if (nonWorkingDays == NonWorkingDays.SaturdaySunday)
            {
                return datelist.Count(d => d.DayOfWeek != DayOfWeek.Saturday &&
                       d.DayOfWeek != DayOfWeek.Friday);
            }
            else
            {
                return datelist.Count(d => d.DayOfWeek != DayOfWeek.Friday &&
                       d.DayOfWeek != DayOfWeek.Saturday);
            }
        }
Returnable answered 22/5, 2014 at 5:42 Comment(0)
S
-1

Check this 1. https://github.com/yatishbalaji/moment-working-days#readme 2. https://www.npmjs.com/package/moment-working-days

It allows you to calculate working days, considering sequence of date(s). You can customize the week off days, and also declare custom dates for holidays (eg: public holidays) to exclude them from being counted as working day(s)

Stackhouse answered 16/12, 2019 at 13:26 Comment(1)
The question is about C# but unfortunately your answer refers to a JS libraryPneumococcus

© 2022 - 2024 — McMap. All rights reserved.