【问题标题】:Number of days in date range, excluding weekends and other dates, in C#C# 中日期范围内的天数,不包括周末和其他日期
【发布时间】:2011-06-30 16:10:39
【问题描述】:

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

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

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

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

【问题讨论】:

  • 可以在此处找到更好的 O(1) 解决方案:stackoverflow.com/questions/1044688

标签: c# date


【解决方案1】:

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

// 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&lt;DateTime&gt;,并使用foreach

如果可能的话,我会尽量避免在此处执行 string 操作 - 从根本上说,这些日期不是字符串,因此如果您可以尽可能地在问题域中工作,它将使事情变得更容易了。

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

作为我自己的开源项目的快速插件,Noda Time 有一组更加多样化的类型来表示日期和时间——在这种情况下,您将使用LocalDate。这样你就不必担心如果“开始”的时间晚于“结束”的时间等会发生什么。另一方面,野田时间还没有真正完成......你需要的位因为这已经准备好并且应该可以正常工作,但 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))
{
    ...
}

【讨论】:

  • 为了避免排除日期的字符串比较,您需要做的就是找到您要排除的日期数(假设没有周末),您可以通过以下方式找到: excludeDates.split( ',')。长度。然后从天数中减去这个。
  • 排除日期可能不一定在开始日期和结束日期之内,所以需要在这里检查 - 这是困难的一部分,意味着我不能按照你建议的方式做.
【解决方案2】:

这是一个包含排除日期、周末和循环的示例。我确实将字符串 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 之间的距离相当大,那么按照其他答案之一中的说明进行数学运算会更好。建议这样做是为了了解迭代日期。

【讨论】:

  • 你可以简单地检查excludeDates.Contents(index)而不是循环for (int i = 0; i &lt; excludeDates.Count; i++) {...},然后整个代码可以简化为两行if (excludeWeekends &amp;&amp; index.DayOfWeek != DayOfWeek.Sunday &amp;&amp; index.DayOfWeek != DayOfWeek.Saturday &amp;&amp; !excludeDates.Contains(index)) count++;
【解决方案3】:

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

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

【讨论】:

    【解决方案4】:

    这是我在 SQL 中使用的另一种方法的伪代码:

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

    【讨论】:

      【解决方案5】:

      这可能有效并避免 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;
      
      }
      

      虽然它没有经过详尽的测试。

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

      【讨论】:

        【解决方案6】:

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

        【讨论】:

          【解决方案7】:
          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;
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2011-03-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-04-06
            相关资源
            最近更新 更多