简体   繁体   English

日期范围内的天数,不包括周末和其他日期,以 C# 为单位

[英]Number of days in date range, excluding weekends and other dates, in C#

I have a C# method like this:我有一个像这样的 C# 方法:

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

What it's supposed to do is calculate the number of days between the startDate and endDate, but optionally needs to exclude weekends and also other dates (passed in as a comma-separated string of dates).它应该做的是计算 startDate 和 endDate 之间的天数,但可选地需要排除周末和其他日期(作为逗号分隔的日期字符串传入)。

I have absolutely no idea how to tackle this.我完全不知道如何解决这个问题。 My gut instinct would be to loop from startDate to endDate and do some string comparisons, but from what I can find out, C# doesn't allow looping through dates in that way - or at least it's not a very elegant way of doing things.我的直觉是从 startDate 循环到 endDate 并进行一些字符串比较,但据我所知,C# 不允许以这种方式循环日期 - 或者至少它不是一种非常优雅的做事方式。

Oh it's really easy to loop through the dates - that's not a problem at all:哦,遍历日期真的很容易——这根本不是问题:

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

You could easily write an IEnumerable<DateTime> too, and use foreach .您也可以轻松编写IEnumerable<DateTime>并使用foreach

I'd try to avoid doing string operations here if possible though - fundamentally these dates aren't strings, so if you can work in the problem domain as far as possible, it'll make things easier.如果可能的话,我会尽量避免在这里进行字符串操作——基本上这些日期不是字符串,所以如果你可以尽可能地在问题域中工作,它会让事情变得更容易。

Of course there may well be more efficient ways than looping, but they'll be harder to get right.当然,可能还有比循环更有效的方法,但它们会更难正确。 If the loop is okay in terms of performance, I'd stick to that.如果循环在性能方面没问题,我会坚持下去。

As a quick plug for my own open source project, Noda Time has a rather more diverse set of types representing dates and times - in this case you'd use LocalDate .作为我自己的开源项目的快速插件, Noda Time有一组更加多样化的类型来表示日期和时间——在这种情况下,您将使用LocalDate That way you don't have to worry about what happens if the time in "start" is later than the time in "end" etc. On the other hand, Noda Time isn't really finished yet... the bits you need for this are ready and should work fine, but it's possible the API could still change in the future.这样你就不必担心如果“开始”的时间晚于“结束”的时间等会发生什么。另一方面,野田时间还没有真正完成......你需要的位因为这已经准备好并且应该可以正常工作,但是 API 将来可能仍然会发生变化。

EDIT: If you do need to loop through dates frequently, you might want something like this extension method (put it in a top-level non-generic static class):编辑:如果您确实需要经常循环访问日期,您可能需要类似这种扩展方法的东西(将其放在顶级非泛型 static 类中):

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

Then:然后:

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

Here's one example that includes the excluded dates, weekends, and looping.这是一个包含排除日期、周末和循环的示例。 I did change the string excludeDates to a List though.我确实将字符串 excludeDates 更改为 List。 Some null checking should be added.应该添加一些 null 检查。

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

EDIT: I do want to point out that I would consider this the quick and dirty method - if you didn't have to do this often.编辑:我确实想指出,如果您不必经常这样做,我会认为这是一种快速而肮脏的方法。 If you're performing this a lot and the distance between the startDate and endDate is rather large it would be much better to do the math as stated in one of the other answers.如果您经常执行此操作并且 startDate 和 endDate 之间的距离相当大,那么按照其他答案之一中所述进行数学运算会更好。 This is suggested in order to get a feel for iterating dates.建议这样做是为了了解迭代日期。

The Subsonic sugar library has a lot of helpers to handle DateTime manipulation. Subsonic 糖库有很多助手来处理 DateTime 操作。

You can find a full list on the Subsonic site and the source code is in github .您可以在Subsonic 网站上找到完整列表,源代码在github中。

Combine with LINQ expressions,结合 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;
    }
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;
}

Here's pseudocode for a different approach which I've used in SQL:这是我在 SQL 中使用的另一种方法的伪代码:

Find the total number of days between the two dates 求两个日期之间的总天数
Subtract number of weekends减去周末数
Remove a day if the start date is a sunday如果开始日期是星期天,则删除一天
Remove a day if the start date is a saturday如果开始日期是星期六,则删除一天
Remove any other days you don't want (see my comment above for how to do this in c#)删除您不想要的任何其他日子(有关如何在 c# 中执行此操作,请参阅我上面的评论)

This might work and avoid a O(n) type solution:这可能有效并避免 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;

}

Its not exhaustively tested though.它虽然没有经过详尽的测试。

To handle the exclusions dates you could loop through those and exclude where they're between start and end (and not a weekend if appropriate).要处理排除日期,您可以遍历这些日期并排除它们在开始和结束之间的位置(如果合适,不是周末)。 This should be a shorter loop than going through all the days between start and end.这应该是一个比开始和结束之间的所有日子更短的循环。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM