2016-07-29 3 views
0

Я хочу написать следующую функцию, которая добавляет n количество рабочих дней до DateTime. Тем не менее, я хочу, чтобы рабочие дни были настраиваемыми:Добавить рабочие дни в DateTime Где рабочие дни настраиваются

public DateTime AddBusinessDays(DateTime dateTime, int n, IEnumerable<DayOfWeek> businessDays) 
{ 
    // ? 
} 

e.g. Среда может быть праздник, поэтому я хочу, чтобы пропустить этот день только:

DateTime.Today.AddBusinessDays(
    7, 
    new DayOfWeek[] 
    { 
     DayOfWeek.Monday, 
     DayOfWeek.Tuesday, 
     DayOfWeek.Thursday, 
     DayOfWeek.Friday, 
     DayOfWeek.Saturday, 
     DayOfWeek.Sunday, 
    }); 

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

UPDATE

Нет рабочие примеры до сих пор, вот некоторые тесты XUnit, чтобы помочь проверить различные сценарии:

[Theory] 
// Zero Values 
[InlineData("01/01/2016", 0, "Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday", "01/01/2016")] 
[InlineData("01/01/2016", 0, "Saturday", "01/01/2016")] 
// Positive Days 
[InlineData("01/01/2016", 1, "Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday", "02/01/2016")] 
[InlineData("01/01/2016", 30, "Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday", "31/01/2016")] 
[InlineData("01/01/2016", 1, "Saturday", "02/01/2016")] 
[InlineData("01/01/2016", 2, "Saturday", "09/01/2016")] 
[InlineData("01/01/2016", 3, "Saturday", "16/01/2016")] 
[InlineData("01/01/2016", 7, "Monday,Tuesday,Wednesday,Thursday,Friday,Saturday", "08/01/2016")] 
// Negative Days  
[InlineData("01/01/2016", -1, "Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday", "31/12/2015")] 
[InlineData("01/01/2016", -31, "Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday", "01/12/2015")] 
[InlineData("01/01/2016", -1, "Saturday", "26/12/2015")] 
[InlineData("01/01/2016", -2, "Saturday", "19/12/2015")] 
[InlineData("01/01/2016", -3, "Saturday", "12/12/2015")] 
public void AddBusinessDays(string start, int days, string businessDays, string expectedEnd) 
{ 
    var daysOfWeek = businessDays.Split(',').Select(x => (DayOfWeek)Enum.Parse(typeof(DayOfWeek), x)); 
    var actualEnd = DateTime.Parse(start).AddBusinessDays(days, daysOfWeek); 
    Assert.Equal(DateTime.Parse(expectedEnd), actualEnd); 
} 

ответ

2

Это должно сделать это. Он использует количество дней, чтобы сохранить счетчик, и только уменьшает его, когда настроенный рабочий день добавляется к дате. С предложениями от Jamiec Я использовал HashSet для ускорения поиска. Тем не менее, это все еще очень линейный алгоритм масштабирования.

public DateTime AddBusinessDays(DateTime dateTime, int n, IEnumerable<DayOfWeek> businessDays) 
{ 
    var tmpDate = dateTime; 

    var bdLookup = new HashSet<DayOfWeek>(businessDays); 

    while (n > 0) 
    { 
     tmpDate = tmpDate.AddDays(1); 
     if (bdLookup.Contains(tmpDate.DayOfWeek)) 
      n--; 
    } 

    return tmpDate; 
} 
+1

Вы бы лучше положить дни недели в том или иную форму HashSet, так что вы не перебор всех элементов - ведь кто-то могло добавляя 10 000 дней до даты, и это собирается получить sloooow – Jamiec

+0

Я только что испытал добавление 10 000 дней, и он сделал это в 8 мс. Так что это довольно медленно. ;) –

+0

его так же просто, как 2 строки change 'var bdLookup = new HashSet (businessDays)' и 'bdLookup.Contains (tmpDate.DayOfWeek)' – Jamiec

2

Постоянного время изменения J. Steen’s answer:

public DateTime AddBusinessDays(DateTime date, int n, IEnumerable<DayOfWeek> businessDays) 
{ 
    var days = new HashSet<DayOfWeek>(businessDays); 

    // add full weeks 
    date = date.AddDays(7 * n/days.Count); 

    // get the remainder 
    n %= days.Count; 

    // add the remaining days; at most 6 times 
    while (n > 0) 
    { 
     date = date.AddDays(1); 
     if (days.Contains(date.DayOfWeek)) 
      n--; 
    } 

    return date; 
} 
+0

О да. Намного быстрее. Я не получаю результата выше 1 мс. Даже до тех пор, пока не переполнится DateTime. Сохранение этих итераций очень приятно. =) –

+0

Продолжительность, которую я получаю, для добавления 400 000 рабочих дней, составляет около 00: 00: 00.00004. Так. Крошечный. –

+2

Ха-ха: D Угадайте, мы закончили оптимизацию этой проблемы, а затем xD – poke