добавление рабочих дней к дате с учетом выходных и праздничных дней - PullRequest
1 голос
/ 08 декабря 2010

с учетом даты и списка праздников, как мне добавить указанное количество рабочих дней к этой дате? Существует множество решений для небольшой проблемы, которая не учитывает праздники (см., например, Добавление дней к дате, но исключая выходные ).

РЕДАКТИРОВАТЬ: я ищу O (1) или хотя бы линейное (по числу выходных) решение.

помогите пожалуйста Спасибо константин

Ответы [ 5 ]

1 голос
/ 08 декабря 2010

Приближается к O (1) (без времени инициализации)

Если вы действительно хотите решение O (1), я надеюсь, что вы не учитываете инициализацию.

Для инициализации:

  • Построить отсортированный список всех дат в запрашиваемом диапазоне, которые являются допустимыми возвращаемыми значениями. (используя что-то вроде кода в ответе от Рика Гарнера)
  • Создать хеш-таблицу с датами из приведенного выше списка, с ключом в качестве даты и индексом в списке в качестве значения

Код инициализации вам понадобится только один раз, и вы кешируете результат.

Для запроса / расчета

 List<DateTime> validWorkdays = // ;
 Dictionary<DateTime, int> lookupIndexOfValidWorkday = // ;

 DateTime AddWorkdays(DateTime start, int count) {
    var startIndex = lookupIndexOfValidWorkday[start];
    return validWorkDays[startIndex + count];
 }

Относительно извлечения из словаря :

Получение или установка значения этого свойства приближается к операции O (1).

O (n) по числу праздников

При условии, что список праздников отсортирован от самых старых до самых новых. ( Кредиты по будням формулы )

DateTime AddBusinessDay(DateTime start, int count, IEnumerable<DateTime> holidays) {
   int daysToAdd = count + ((count/ 5) * 2) + ((((int)start.DayOfWeek + (count % 5)) >= 5) ? 2 : 0);
   var end = start.AddDays(daysToAdd);
   foreach(var dt in holidays) {
     if (dt >= start && dt <= end) {
        end = end.AddDays(1);
        if (end.DayOfWeek == DayOfWeek.Saterday) {
          end = end.AddDays(2);
        }
     }
   }
   return end;
}    

Этот метод может быть оптимизирован.

Очень сложно создать простую формулу, которая просто вычисляет результат, как ответы на вопрос, с которым вы связаны. Потому что, когда вы приспосабливаетесь к праздникам, вы должны учитывать новые праздники, которые могут попасть в ваш диапазон. В выходные дни вы знаете, что между ними установлен фиксированный интервал.

0 голосов
/ 19 октября 2013

// Ниже код работает ... пожалуйста, дайте мне знать, если у вас есть какие-либо проблемы

DateTime AddBusinessDays(int noofDays, DateTime dtCurrent)
    {
        var holidays = new List<DateTime>() { new DateTime(2013, 10, 22), new DateTime(2013, 10, 28)};

        DateTime tempdt = new DateTime(dtCurrent.Year, dtCurrent.Month, dtCurrent.Day);
        // if starting day is non working day adjust to next working day
        tempdt = ExcludeNotWorkingDay(tempdt, holidays);

        // if starting day is non working day adjust to next working day then minus 1 day in noofadding days
        if (tempdt.Date > dtCurrent.Date && !(noofDays == 0))
            noofDays = noofDays - 1;

        while (noofDays > 0)
        {   
            tempdt = tempdt.AddDays(1);
            // if day is non working day adjust to next working day
            tempdt = ExcludeNotWorkingDay(tempdt, holidays);
            noofDays = noofDays - 1;
        }

        return tempdt;
    }
    DateTime ExcludeNotWorkingDay(DateTime dtCurrent, List<DateTime> holidays)
    {
        while (!IsWorkDay(dtCurrent, holidays))
        {
            dtCurrent = dtCurrent.AddDays(1);
        }
        return dtCurrent;
    }
    bool IsWorkDay(DateTime dtCurrent, List<DateTime> holidays)
    {
        if ((dtCurrent.DayOfWeek == DayOfWeek.Saturday || dtCurrent.DayOfWeek == DayOfWeek.Sunday ||
             holidays.Contains(dtCurrent)))
        {
            return false;
        }
        else
        {
            return true;
        }
    }
0 голосов
/ 08 декабря 2010
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

namespace DateThing
{
    class Program
    {
        static void Main(string[] args)
        {
            var holidays = new List<DateTime>()
                               {
                                   new DateTime(2010, 12, 25),
                                   new DateTime(2010, 12, 26)
                               };


            var futureDate = CalculateFutureDate(DateTime.Today, 20, holidays);

        }

        static DateTime CalculateFutureDate(DateTime fromDate, int numberofWorkDays, ICollection<DateTime> holidays)
        {
            var futureDate = fromDate;

            for (var i = 0; i < numberofWorkDays; i++ )
            {
                if (futureDate.DayOfWeek == DayOfWeek.Saturday || futureDate.DayOfWeek == DayOfWeek.Sunday ||
                    (holidays != null && holidays.Contains(futureDate)))
                    futureDate = futureDate.AddDays(1); // Increase FutureDate by one because of condition

                futureDate = futureDate.AddDays(1); // Add a working day
            }
            return futureDate;
        }
    }
}
0 голосов
/ 08 декабря 2010

Попробуйте это ......

 private DateTime CalculateFutureDate(DateTime fromDate, int numberofWorkDays, ICollection<DateTime> holidays)
    {
        var futureDate = fromDate;
        var daterange = Enumerable.Range(1, numberofWorkDays * 2);
        var dateSet = daterange.Select (d => futureDate.AddDays(d));
        var dateSetElim = dateSet.Except(holidays).Except(dateSet.Where( s =>s.DayOfWeek == DayOfWeek.Sunday).Except(dateSet.Where  (s=>s.DayOfWeek==DayOfWeek.Saturday) ));

        //zero-based array
        futureDate = dateSetElim.ElementAt(numberofWorkDays-1);
        return futureDate;
    }
0 голосов
/ 08 декабря 2010

Нечто подобное возможно

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DateThing
{
    class Program
    {
        static void Main(string[] args)
        {
            var holidays = new List<DateTime>()
                               {
                                   new DateTime(2010, 12, 25),
                                   new DateTime(2010, 12, 26)
                               };


            var workDays = GetNumberOfWorkDays(DateTime.Today, new DateTime(2011, 1, 1), holidays);
        }

        static int GetNumberOfWorkDays(DateTime fromDate, DateTime toDate, ICollection<DateTime> holidays)
        {
            var days = 0;
            for (var i = fromDate; i < toDate; )
            {
                if (i.DayOfWeek != DayOfWeek.Saturday && i.DayOfWeek != DayOfWeek.Sunday && 
                    (holidays != null && !holidays.Contains(i)))
                    days++;

                i = i.AddDays(1);
            }
            return days;
        }
    }


}
...