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

时间:2011-06-30 16:10:40

标签: c# date

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

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

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

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

7 个答案:

答案 0 :(得分:10)

哦,很容易遍历日期 - 这根本不是问题:

// 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<DateTime>,然后使用foreach

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

当然可能有更有效的方式而不是循环,但它们更难以正确。如果循环在性能方面没问题,我会坚持下去。

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

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

public static IEnumerable<DateTime> 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))
{
    ...
}

答案 1 :(得分:9)

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

    public static int DaysLeft(DateTime startDate, DateTime endDate, Boolean excludeWeekends, List<DateTime> 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之间的距离相当大,那么按照其他一个答案中的说明进行数学运算会好得多。建议这样做是为了感受迭代日期。

答案 2 :(得分:1)

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

您可以在Subsonic site上找到完整列表,源代码位于github

答案 3 :(得分:0)

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

Find the total number of days between the two dates
减去周末数量 如果开始日期是星期日,请删除一天 如果开始日期是星期六,则删除一天 删除您不想要的任何其他日子(请参阅上面的评论,了解如何在c#中执行此操作)

答案 4 :(得分:0)

这可能会起作用并避免使用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;

}

虽然没有详尽的测试。

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

答案 5 :(得分:0)

与LINQ表达式结合,

        public int GetNoOfLeaveDays(DateTime fromDate, DateTime toDate, Boolean excludeWeekends, List<DateTime> 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;
    }

答案 6 :(得分:0)

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;
}