C#中日期范围内的天数,不包括周末和其他日期

我有一个像这样的C#方法:

public static int DaysLeft(DateTime startDate, DateTime endDate, Boolean excludeWeekends, String excludeDates) { } 

它应该做的是计算startDate和endDate之间的天数,但是可选地需要排除周末和其他日期(以逗号分隔的日期字符串传递)。

我完全不知道如何解决这个问题。 我的直觉是从startDate循环到endDate并进行一些字符串比较,但从我可以发现的结果来看,C#不允许以这种方式循环日期 – 或者至少它不是一种非常优雅的做事方式。

这是一个包含排除日期,周末和循环的示例。 我确实将字符串excludeDates更改为List。 应添加一些空检查。

  public static int DaysLeft(DateTime startDate, DateTime endDate, Boolean excludeWeekends, List excludeDates) { int count = 0; for (DateTime index = startDate; index < endDate; index = index.AddDays(1)) { if (excludeWeekends && index.DayOfWeek != DayOfWeek.Sunday && index.DayOfWeek != DayOfWeek.Saturday) { bool excluded = false; ; for (int i = 0; i < excludeDates.Count; i++) { if (index.Date.CompareTo(excludeDates[i].Date) == 0) { excluded = true; break; } } if (!excluded) { count++; } } } return count; } 

编辑:我想指出,我会认为这是一个快速而肮脏的方法 - 如果你不必经常这样做。 如果你执行这么多,并且startDate和endDate之间的距离相当大,那么按照其他一个答案中的说明进行数学运算会好得多。 建议这样可以了解迭代日期。

哦,循环日期真的很容易 – 这根本不是问题:

 // I'm assuming you want <= to give an *inclusive* end date... for (DateTime date = start; date <= end; date = date.AddDays(1)) { // Do stuff with date } 

您也可以轻松编写IEnumerable ,并使用foreach

如果可能的话,我会尽量避免在这里进行字符串操作 - 从根本上说这些日期不是字符串,所以如果你可以尽可能地在问题域中工作,它会让事情变得更容易。

当然,除了循环之外,可能有更有效的方法,但它们将更难以正确。 如果循环在性能方面没问题,我会坚持这一点。

作为我自己的开源项目的快速插件, Noda Time有一组更多样化的类型代表日期和时间 - 在这种情况下,你使用LocalDate 。 这样你就不必担心如果“开始”的时间晚于“结束”的时间等会发生什么。另一方面,Noda Time还没有真正完成......你需要的位数为此已做好准备,应该可以正常工作,但API可能在未来仍有可能发生变化。

编辑:如果你确实需要经常循环日期,你可能想要这样的扩展方法(把它放在顶级非generics静态类):

 public static IEnumerable To(this DateTime start, DateTime end) { Date endDate = end.Date; for (DateTime date = start.Date; date <= endDate; date = date.AddDays(1)) { yield return date; } } 

然后:

 foreach (DateTime date in start.To(end)) { ... } 

Subsonic糖库有很多帮助器来处理DateTime操作。

您可以在Subsonic站点上找到完整列表,源代码位于github中 。

这是我在SQL中使用的不同方法的伪代码:

查找两个日期之间的总天数
减去周末数量
如果开始日期是星期日,请删除一天
如果开始日期是星期六,则删除一天
删除您不想要的任何其他日子(请参阅上面的评论,了解如何在c#中执行此操作)

这可能会起作用并避免使用O(n)类型的解决方案:

 public int DaysLeft(DateTime startDate, DateTime endDate, Boolean excludeWeekends, String excludeDates) { //Work out days in range int days = (int)endDate.Subtract(startDate).TotalDays + 1; if (excludeWeekends) { //Remove most weekends by removing 2 in 7 days (rounded down) days -= ((int)Math.Floor((decimal)(days / 7)) * 2); if (startDate.DayOfWeek == DayOfWeek.Sunday) days -= 1; if (startDate.DayOfWeek == DayOfWeek.Saturday) days -= 2; } return days; } 

虽然没有详尽的测试。

要处理排除日期,您可以遍历这些日期并排除它们在开始和结束之间的位置(如果合适,则不包括周末)。 这应该是比开始和结束之间的所有日子更短的循环。

结合LINQ表达式,

  public int GetNoOfLeaveDays(DateTime fromDate, DateTime toDate, Boolean excludeWeekends, List excludeDates) { var count = 0; for (DateTime index = fromDate; index <= toDate; index = index.AddDays(1)) { if (!excludeWeekends || index.DayOfWeek == DayOfWeek.Saturday || index.DayOfWeek == DayOfWeek.Sunday) continue; var excluded = excludeDates.Any(t => index.Date.CompareTo(t.Date) == 0); if (!excluded) count++; } return count; } 
 private int workingdays(int month,int year) { int daysInMonth = 0; int days = DateTime.DaysInMonth(year, month); for (int i = 1; i <= days; i++) { DateTime day = new DateTime(year, month, i); if (day.DayOfWeek != DayOfWeek.Sunday && day.DayOfWeek != DayOfWeek.Saturday) { daysInMonth++; } } return daysInMonth; }