C #: Добавление рабочих дней с определенной даты - PullRequest
9 голосов
/ 15 сентября 2010

У меня проблемы с этим. Я создаю метод, который добавляет рабочие дни на определенную дату. например, я хочу добавить 3 рабочих дня к 15 сентября 2010 года (среда), метод вернет 20 сентября (понедельник следующей недели). он игнорирует субботу и воскресенье, потому что это нерабочий день ..

Примерно так в C #:

DateTime AddWorkingDays(DateTime specificDate, int workingDaysToAdd)
{
   return specificDate + (workingDaysToAdd - (all saturdays and sundays))
}

Я не рассматриваю специальные праздники в вычислениях, я просто буквально хочу добавить дни, кроме субботы и воскресенья. =)

Ответы [ 6 ]

18 голосов
/ 15 сентября 2010

Если вам не нужно рассматривать праздники, я бы посоветовал вам сделать что-то вроде этого:

public static DateTime AddWorkingDays(DateTime specificDate,
                                      int workingDaysToAdd)
{
    int completeWeeks = workingDaysToAdd / 5;
    DateTime date = specificDate.AddDays(completeWeeks * 7);
    workingDaysToAdd = workingDaysToAdd % 5;
    for (int i = 0; i < workingDaysToAdd; i++)
    {
        date = date.AddDays(1);
        while (!IsWeekDay(date))
        {
            date = date.AddDays(1);
        }
    }
    return date;
}

private static bool IsWeekDay(DateTime date)
{
    DayOfWeek day = date.DayOfWeek;
    return day != DayOfWeek.Saturday && day != DayOfWeek.Sunday;
}

Это неэффективно, но легко понять. Для эффективной версии вы должны добавить количество полных недель для добавления, как и прежде, но затем иметь сопоставление с любым «текущим днем ​​недели» и «оставшимися рабочими днями» для добавления к « фактическому *» 1005 * дней, чтобы добавить ". Тогда вы можете просто определить общее количество дней, которое нужно добавить, и сделать это за один вызов.

РЕДАКТИРОВАТЬ: С точки зрения уровня неэффективности ... это действительно не очень плохо. Он будет выполнять только ручные проверки «это выходные» в течение 4 дней, что не так уж плохо. В частности, несмотря на заявления Игора (действующие на момент публикации), он намного быстрее, чем его подход, несмотря на некорректные тесты;)

Обратите внимание, что он может еще не обрабатывать отрицательные входные данные - я не проверял.

Одна из причин использования подхода, который я использую, заключается в том, что он не полагается ни на меня, ни на читателя кода, знающих, каковы значения в перечислении DayOfWeek. Мне все равно, будь то 0-6, 1-7, понедельник-воскресенье, суббота-пятница ... или даже если есть совершенно странные значения. Я сравниваю только на равенство, что делает код более «очевидно правильным».

1 голос
/ 15 сентября 2010

Прохладный способ (я думаю) заключен в методе расширения, например:

public static class DateTimeExtensions
{
    public static DateTime AddWorkingDays(this DateTime self, int days)
    {
        self = self.AddDays(days);
        while (self.DayOfWeek == DayOfWeek.Saturday || self.DayOfWeek == DayOfWeek.Sunday)
        {
            self = self.AddDays(1);
        }

        return self;
    }
}

, поэтому ваш окончательный код будет выглядеть так:

specificDate.AddWorkingDays(3);
0 голосов
/ 10 июня 2016

Мне кажется, это самый чистый способ:

public static DateTime AddWorkingDays(DateTime date, int daysToAdd)
{
    while (daysToAdd > 0)
    {
        date = date.AddDays(1);

        if (date.DayOfWeek != DayOfWeek.Saturday && date.DayOfWeek != DayOfWeek.Sunday) daysToAdd -= 1;
    }

    return date;
}
0 голосов
/ 02 декабря 2014

Это старый пост, но кто-то может быть заинтересован в расширении, которое обрабатывает и отрицательные дни. (Я переделал @Jon ответ)

    public static DateTime AddWeekDays(this DateTime start, int days)
    {
        int direction = Math.Sign(days);

        int completeWeeks = days / 5;
        int remaining = days % 5;

        DateTime end = start.AddDays(completeWeeks * 7);

        for (int i = 0; i < remaining * direction; i++)
        {
            end = end.AddDays(direction * 1);
            while (!IsWeekDay(end))
            {
                end = end.AddDays(direction * 1);
            }
        }
        return end;
    }

    private static bool IsWeekDay(DateTime date)
    {
        DayOfWeek day = date.DayOfWeek;
        return day != DayOfWeek.Saturday && day != DayOfWeek.Sunday;
    }
0 голосов
/ 15 сентября 2010
int foundWorkingDays = 0;
while (foundWorkingDays < workingDaysToAdd)
{ 
  specificDate= specificDate.AddDays(1); 
  if(specificDate.DayOfWeek != DayOfWeek.Sunday && specificDate.DayOfWeek != DayOfWeek.Saturday)
     foundWorkingDays++;

}
return specificDate;

ДОБАВЛЕНО:

class Program
    {

        public static DateTime AddWorkingDays(DateTime specificDate,
                                      int workingDaysToAdd)
        {
            int completeWeeks = workingDaysToAdd / 5;
            DateTime date = specificDate.AddDays(completeWeeks * 7);
            workingDaysToAdd = workingDaysToAdd % 5;
            for (int i = 0; i < workingDaysToAdd; i++)
            {
                date = date.AddDays(1);
                while (!IsWeekDay(date))
                {
                    date = date.AddDays(1);
                }
            }
            return date;
        }

        private static bool IsWeekDay(DateTime date)
        {
            DayOfWeek day = date.DayOfWeek;
            return day != DayOfWeek.Saturday && day != DayOfWeek.Sunday;
        }

        public static DateTime MyAddWorkingDays(DateTime specificDate,
                                      int workingDaysToAdd)
        {
            int foundWorkingDays = 0;
            while (foundWorkingDays < workingDaysToAdd)
            {
                specificDate = specificDate.AddDays(1);
                if (specificDate.DayOfWeek != DayOfWeek.Sunday && specificDate.DayOfWeek != DayOfWeek.Saturday)
                    foundWorkingDays++;

            }
            return specificDate;
        }


        static void Main(string[] args)
        {

            DateTime specificDate = DateTime.Now;

            Stopwatch globalTimer = Stopwatch.StartNew();
            Console.WriteLine(AddWorkingDays(specificDate, 300));  // 100000 :)
            globalTimer.Stop();
            Console.WriteLine(globalTimer.ElapsedMilliseconds);

            globalTimer = Stopwatch.StartNew();
            Console.WriteLine(MyAddWorkingDays(specificDate, 300)); // 100000 :)
            globalTimer.Stop();
            Console.WriteLine(globalTimer.ElapsedMilliseconds);



            Console.ReadLine();
        }
    }
0 голосов
/ 15 сентября 2010

Вот что вам нужно:

Обновлено:

public static DateTime AddWeekdays(DateTime start, int days)
    {
        int remainder = days % 5;
        int weekendDays = (days / 5) * 2;

        DateTime end = start.AddDays(remainder);

        if (start.DayOfWeek == DayOfWeek.Saturday && days > 0)
        {
            // fix for saturday.
            end = end.AddDays(-1);
        }

        if (end.DayOfWeek == DayOfWeek.Saturday && days > 0)
        {
            // add two days for landing on saturday
            end = end.AddDays(2);
        }
        else if (end.DayOfWeek < start.DayOfWeek)
        {
            // add two days for rounding the weekend
            end = end.AddDays(2);
        }

        // add the remaining days
        return end.AddDays(days + weekendDays - remainder);
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...