Calculate the number of business days between two dates?

后端 未结 30 1193
悲&欢浪女
悲&欢浪女 2020-11-22 14:54

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

相关标签:
30条回答
  • 2020-11-22 15:29

    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;
        }
    
    0 讨论(0)
  • 2020-11-22 15:30

    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;
        }
    
    0 讨论(0)
  • 2020-11-22 15:33
        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);
        }
    
    0 讨论(0)
  • 2020-11-22 15:34

    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;
    }
    
    0 讨论(0)
  • 2020-11-22 15:35

    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;
        }
    
    0 讨论(0)
  • 2020-11-22 15:36

    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.

    0 讨论(0)
提交回复
热议问题