C# 计算两个日期之间的工作日数?

C# 计算两个日期之间的工作日数?,c#,datetime,C#,Datetime,在C#中,如何计算两个日期之间的业务(或工作日)天数?定义DateTime的扩展方法,如下所示: public static class DateTimeExtensions { public static bool IsWorkingDay(this DateTime date) { return date.DayOfWeek != DayOfWeek.Saturday && date.DayOfWeek != DayOf

在C#中,如何计算两个日期之间的业务(或工作日)天数?

定义DateTime的扩展方法,如下所示:

public static class DateTimeExtensions
{
    public static bool IsWorkingDay(this DateTime date)
    {
        return date.DayOfWeek != DayOfWeek.Saturday
            && date.DayOfWeek != DayOfWeek.Sunday;
    }
}
然后,在Where子句中使用,以筛选更广泛的日期列表:

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

// filter dates by working day's  
var countOfWorkDays = allDates
     .Where(day => day.IsWorkingDay())
     .Count() ;

这里有一些代码可以实现这一目的,包括瑞典的假期,但您可以调整要计算的假期。请注意,我添加了一个您可能希望删除的限制,但它是针对基于web的系统的,我不希望任何人输入某个巨大的日期来控制流程

  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;
    }
public static int GetWorkdays(DateTime from,DateTime to)
{
整数极限=9999;
int计数器=0;
日期时间当前=从;
int结果=0;
如果(从>到)
{
日期时间温度=从;
从=到;
to=温度;
}
如果(从>=到)
{
返回0;
}

而(当前我以前有过这样的任务,我已经找到了解决方案。 我会避免列举可以避免的时间间隔,这里就是这种情况。我甚至没有提到创建一堆DateTime实例,正如我在上面的一个答案中所看到的。这确实是在浪费处理能力。特别是在现实世界中,当你不得不检查几个月的时间间隔时。 请参见下面我的代码和注释

    /// <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;
    }
现在的结果是:

  • 周五至周五->1
  • 周六至周六->0
  • 周日至周日->0
  • 周五至周六->1
  • 周五至周日->1
  • 星期五至星期一->2
  • 周六至周一->1
  • 周日至周一->1
  • 周一至周一->1

    • 好的。我想是时候发布正确的答案了:

      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;
      }
      
      原始资料来源:


      我知道这个问题已经解决了,但我想我可以提供一个更直观的答案,将来可能会帮助其他访问者

      以下是我的看法:

      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);
      }
      
      这是我最初的意见:

      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;
      }
      
      public int GetWorkingDays(DateTime from,DateTime to)
      {
      var totalDays=0;
      对于(var日期=从;日期<到;日期=日期。添加天数(1))
      {
      如果(date.DayOfWeek!=DayOfWeek.Saturday
      &&date.DayOfWeek!=DayOfWeek.Sunday)
      totalDays++;
      }
      返回总天数;
      }
      
      我认为上述答案没有一个是正确的。没有一个能解决所有的特殊情况,例如日期在周末开始和结束,日期在星期五开始,下星期一结束,等等。例如,它将从工作日中减去一整天,从而得出错误的结果

      无论如何,这是我的解决方案,它非常有效、简单,适用于所有情况。诀窍就是找到开始和结束日期的前一个星期一,然后在周末开始和结束时进行少量补偿:

      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;
          }
      
      公共双工作日(日期时间开始日期、日期时间结束日期){
      双周日;
      双倍天数=结束日期。减去(开始日期)。总天数;
      如果(第0天)周末天数-=diffStart;
      如果(差分>0)周末天数+=差分;
      返回日-周日;
      }
      
      我将与大家分享我的解决方案。它对我很有效,也许我只是没有注意到/知道有一个bug。 我从第一个不完整的星期开始,如果有的话。 完整的一周是从星期日到星期六,因此如果(int)_now.DayOfWeek不是0(星期日),则第一周是不完整的

      我只需将第一周的星期六的第一周计数减去1,然后将其添加到新计数中

      然后我得到最后一个不完整的星期,然后减去1作为星期天,然后加上新的计数

      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;
              }
      
      最后,将完整周数乘以5(工作日)添加到新计数中

      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;
              }
      
      public int RemoveNonWorkingDays(int numberOfDays){
      int工作日=0;
      int firstWeek=7-(int)_now.DayOfWeek;
      如果(第一周<7){
      如果(第一周>天数)
      返回天数;
      工作日+=第一周-1;
      numberOfDays-=第一周;
      }
      int lastWeek=天数%7;
      如果(上周>0){
      numberOfDays-=上周;
      工作日+=上周-1;
      }
      工作日+=(天数/7)*5;
      返回工作日;
      }
      
      我使用了以下代码来考虑银行假期:

      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; }
      }
      

      我很难找到这段代码的可靠TSQL版本。下面是对的转换,添加了假期表,该表应用于预先计算假期

      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
      
      创建表dbo.Holiday
      (
      HolidayDt日期不为空,
      名称NVARCHAR(50)不为空,
      IsWeekday位不为空,
      约束PK_假日主键(HolidayDt)
      )
      去
      创建索引IDX_Holiday ON Holiday(HolidayDt,IsWeekday)
      去
      创建函数dbo.GetBusinessDays
      (
      @第一天日期时间,
      @最后日期时间
      ) 
      返回整数
      像
      开始
      声明@BusinessDays INT、@FullWeekCount INT
      选择@FirstDay=CONVERT(日期时间,CONVERT(日期,@FirstDay))
      ,@LastDay=CONVERT(日期时间,CONVERT(日期,@LastDay))
      如果@FirstDay>@LastDay
      返回NULL;
      选择@BusinessDays=DATEDIFF(DAY、@FirstDay、@LastDay)+1
      选择@FullWeekCount=@BusinessDays/7;
      --找出在超过整周的时间内是否有周末
      如果@BusinessDays>(@FullWeekCount*7)
      开始
      --我们来这里是想知道周末是一天还是两天
      --减去整周后剩余的时间间隔内
      声明@firstDayOfWeek INT,@lastDayOfWeek INT;
      选择@firstDayOfWeek=DATEPART(DW,@FirstDay),@lastDayOfWeek=DATEPART(DW,@LastDay);
      如果@lastDayOfWeek<@firstDayOfWe
      
      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
      
          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);
          }
      
      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);
          }
      }
      
       /// <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;
          }
      
      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;
              }
          }
      }
      
      /// <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;
      }
      
          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;
          }
      
      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;
          }
      
          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;
          }
      
      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);
      }
      
      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];
      }
      
      [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);
          }
      }
      
      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;
          }
      }
      
      [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);
          }
      }
      
      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();
              } 
      
      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
              }
      
      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));
      
              }
      
      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;
      }
      
          // 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;
          }
      
              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++;
                  }
              }
      
      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;
      }
      
      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;
          }
      
          var totaldays = (endDate - startDate).TotalDays + 1; // add one to include the first day to
          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;
      }
      
      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;
      }
      
          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;
          }
      
      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;
      }
      
      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
      }
      
        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;
          }