这是一个很好的算法,可以找到给定月份的每周?

时间:2011-10-18 17:25:03

标签: c# .net algorithm

我需要花一个月(定义为开始日期和结束日期)并返回该月每周的一组日期范围。一周定义为周日至周六。如果您在开始栏中双击Windows日期,那么可视化它的好方法是:

http://i54.tinypic.com/j58sh0.png

2011年10月有6周:10 / 1-10 / 1,10 / 2-10 / 8,10 / 9-10 / 15,10 / 16-10 / 22,10 / 23-10 / 29和10 / 30-10 / 31。

我可以将每周描述为结构:

   struct Range
   {
      public DateTime Start;
      public DateTime End;

      public Range(DateTime start, DateTime end)
      {
         Start = start;
         End = end;
      }
   }

我需要编写一个需要一个月的函数并返回一个范围数组。这是我的第一次尝试,它似乎起作用并解决了明显的边缘情况:

public static IEnumerable<Range> GetRange(DateTime start, DateTime end)
{
   DateTime curStart = start;
   DateTime curPtr = start;
   do
   {
      if (curPtr.DayOfWeek == DayOfWeek.Saturday)
      {
         yield return new Range(curStart, curPtr);
         curStart = curPtr.AddDays(1);
      }

      curPtr = curPtr.AddDays(1);
   } while (curPtr <= end);

   if(curStart <= end)
      yield return new Range(curStart, end);
}

我想知道是否有更清洁或更明显的方法来做同样的事情。我并不过分关注性能,但我想提高代码可读性并使算法更简洁。也许有一个非常有创意的解决方案涉及单个LINQ表达式或其他东西。谢谢!

1 个答案:

答案 0 :(得分:1)

这是基于Previti建议的简单增加7,准备国际使用。如果你的C#是&lt; 4.0,删除默认参数= DayOfWeek.Sunday

public static IEnumerable<Range> GetRange(DateTime start, DateTime end, DayOfWeek startOfTheWeek = DayOfWeek.Sunday)
{
    if (start > end)
    {
        throw new ArgumentException();
    }

    // We "round" the dates to the beginning of the day each
    start = start.Date;
    end = end.Date;

    // The first week. It could be "shorter" than normal. We return it "manually" here
    // The 6 + startOfWeek - start.DayOfWeek will give us the number of days that you
    // have to add to complete the week. It's mod 7. It's based on the idea that 
    // the starting day of the week is a parameter.
    DateTime curDay = new DateTime(Math.Min(start.AddDays((6 + (int)startOfTheWeek - (int)start.DayOfWeek) % 7).Ticks, end.Ticks), start.Kind);

    yield return new Range(start, curDay);

    curDay = curDay.AddDays(1);

    while (curDay <= end)
    {
        // Each time we add 7 (SIX) days. This is because the difference between
        // as considered by the problem, it's only 6 * 24 hours (because the week
        // doesn't end at 23:59:59 of the last day, but at the beginning of that day)
        DateTime nextDay = new DateTime(Math.Min(curDay.AddDays(6).Ticks, end.Ticks), start.Kind);

        yield return new Range(curDay, nextDay);

        // The start of the next week
        curDay = nextDay.AddDays(1);
    }
}

一些小注释:Math.Min没有为DateTime定义,所以我通过Ticks的{​​{1}}进行了比较并进行了比较。然后我重建了DateTime。我总是使用DateTime日期的DateTimeKind

调试start代码时,请记住使用yieldToList“实现”结果,否则代码将不会执行: - )