Ejemplo n.º 1
0
 private DateTime GetHolidayDate(int year, HolidayDefinition holidayDefinition)
 {
     return(Enum.Parse <HolidayPlacementStrategy>(holidayDefinition.PlacementStrategy) switch
     {
         HolidayPlacementStrategy.FixedDate => DateUtils.CalculateFixedDatePlacement(year,
                                                                                     holidayDefinition.Month, holidayDefinition.Day),
         HolidayPlacementStrategy.FixedDay => DateUtils.CalculateFixedDayPlacement(year, holidayDefinition.Month,
                                                                                   holidayDefinition.DayOfWeek, holidayDefinition.WeekOfMonth),
         HolidayPlacementStrategy.FixedDateNonWeekend => DateUtils.CalculateFixedDateNonWeekendPlacement(year,
                                                                                                         holidayDefinition.Month, holidayDefinition.Day),
         _ => throw new InvalidOperationException($"'{holidayDefinition.PlacementStrategy}' is not handled")
     });
Ejemplo n.º 2
0
        /// <inheritdoc />
        public async Task <long> CalculateWorkingDays(DateTime from, DateTime to)
        {
            var totalDays = (long)(to - from).TotalDays + 1;

            if (totalDays <= 0)
            {
                return(0);
            }

            // Retrieve all relevant holidays definitions from data source, pull all if the total days elapses a year
            var holidays = await _holidayDefinitionRepository.Query
                           .Where(totalDays < 365?HolidayDefinition.BetweenMonths(from, to) : h => true)
                           .ToListAsync();

            // Efficiently calculate whole years, removing in batch. Skipping the last remainder of a year
            // Additional performance could be achieved with asynchronous batching
            var removalDays = 0L;
            var fullYears   = totalDays / 365;

            for (var y = 0; y < fullYears; y++)
            {
                // Determine the count of all holidays that rest on a weekday
                removalDays = holidays
                              .Select(h => GetHolidayDate(from.Year + y, h).DayOfWeek)
                              .Aggregate(removalDays, (days, holidayDay) =>
                                         days + (holidayDay != DayOfWeek.Saturday && holidayDay != DayOfWeek.Sunday ? 1 : 0));
            }

            // Calculate the overflow of days
            var excessDays = totalDays % (DateTime.IsLeapYear(to.Year) ? 366 : 365);

            if (excessDays > 0)
            {
                // Sum all holidays that exist within the partial range that are not on a weekend
                removalDays += holidays
                               .Where(h => h.Month >= to.AddDays(-excessDays).Month)
                               .Count(h =>
                {
                    // Conditional as to what year the holiday falls on, i.e. 1/06/2020 - 1/05/2021
                    var holidayDate = GetHolidayDate(to.Year, h);
                    // Assume that if it isn't within the last year, it is in the previous year
                    if (holidayDate > to)
                    {
                        holidayDate = GetHolidayDate(to.Year - 1, h);
                    }
                    return(holidayDate >= from && holidayDate <= to &&
                           holidayDate.DayOfWeek != DayOfWeek.Saturday &&
                           holidayDate.DayOfWeek != DayOfWeek.Sunday);
                });
            }

            // Account for weekends in bulk
            var weekends = totalDays / 7 * 2;

            // Cycle through remaining days (Maximum 6) to determine how many additional weekends
            var remainingWeekOverflow = totalDays % 7;

            if (remainingWeekOverflow > 0)
            {
                var lastProcessedDate = to.AddDays(-remainingWeekOverflow);
                // TODO : There is a more optimal way, but in the interest of time the performance increase is negligible
                for (var d = 1; d <= remainingWeekOverflow; d++)
                {
                    var day = lastProcessedDate.AddDays(d).DayOfWeek;
                    if (day == DayOfWeek.Saturday || day == DayOfWeek.Sunday)
                    {
                        weekends++;
                    }
                }
            }

            removalDays += weekends;
            return(totalDays - removalDays);
        }
Ejemplo n.º 3
0
 static HolidayUtils()
 {
     HolidayDefinitions = new HolidayDefinition[] {
         new HolidayDefinition()
         {
             Title = "元日", Month = 1, Day = 1
         },
         new HolidayDefinition()
         {
             Title = "成人の日", Month = 1, Day = 15, EndYear = 1999
         },
         new HolidayDefinition()
         {
             Title = "成人の日", Month = 1, HappyMondayWeek = 2, StartYear = 2000
         },
         new HolidayDefinition()
         {
             Title = "建国記念の日", Month = 2, Day = 11, StartYear = 1967
         },
         new HolidayDefinition()
         {
             Title = "天皇誕生日", Month = 4, Day = 29, EndYear = 1988
         },
         new HolidayDefinition()
         {
             Title = "みどりの日", Month = 4, Day = 29, StartYear = 1989, EndYear = 2006
         },
         new HolidayDefinition()
         {
             Title = "昭和の日", Month = 4, Day = 29, StartYear = 2007
         },
         new HolidayDefinition()
         {
             Title = "憲法記念日", Month = 5, Day = 3
         },
         new HolidayDefinition()
         {
             Title = "みどりの日", Month = 5, Day = 4, StartYear = 2007
         },
         new HolidayDefinition()
         {
             Title = "こどもの日", Month = 5, Day = 5
         },
         new HolidayDefinition()
         {
             Title = "海の日", Month = 7, Day = 20, StartYear = 1996, EndYear = 2002
         },
         new HolidayDefinition()
         {
             Title = "海の日", Month = 7, HappyMondayWeek = 3, StartYear = 2003
         },
         new HolidayDefinition()
         {
             Title = "山の日", Month = 8, Day = 11, StartYear = 2016
         },
         new HolidayDefinition()
         {
             Title = "敬老の日", Month = 9, Day = 15, StartYear = 1966, EndYear = 2002
         },
         new HolidayDefinition()
         {
             Title = "敬老の日", Month = 9, HappyMondayWeek = 3, StartYear = 2003
         },
         new HolidayDefinition()
         {
             Title = "体育の日", Month = 10, Day = 10, EndYear = 1999
         },
         new HolidayDefinition()
         {
             Title = "体育の日", Month = 10, HappyMondayWeek = 2, StartYear = 2000
         },
         new HolidayDefinition()
         {
             Title = "文化の日", Month = 11, Day = 3
         },
         new HolidayDefinition()
         {
             Title = "勤労感謝の日", Month = 11, Day = 23
         },
         new HolidayDefinition()
         {
             Title = "天皇誕生日", Month = 12, Day = 23, StartYear = 1989
         },
     };
 }