2016-07-29 87 views
0

我想要編寫以下功能,將n工作日數添加到DateTime。但是,我希望工作日可以配置:將營業日添加到日期時間營業日可配置

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

例如,週三可能是假的,所以我想只跳過這一天:

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線更換容易'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

噢。快多了。我在1ms以上沒有結果。直到幾乎溢出DateTime纔開始。保存這些迭代是非常好的。 =) –

+0

我獲得的期限爲40000個工作日,大約爲00:00:00.00004。所以。小。 –

+2

哈哈:D猜猜我們已經完成了優化這個問題,然後xD – poke