在日期之间的整个星期分组 - LINQ

时间:2016-09-13 15:16:38

标签: c# linq datetime

我知道如何计算两个日期之间的周数。

我有一个日期(开始日期和结束日期)。 是否有可能获得Tuple<DateTime, DateTime>item_1是一周开始日且item_2结束的内容?我的意思是我最终希望看到List<Tuple<DateTime, DateTime>>

例如我的期间是从2016年9月13日到2016年10月5日 因此,我希望看到一个包含两个主题的列表:

  1. 19/09/16 - 25/09/16
  2. 26/09/16 - 2/10/16
  3. 我为此写了一个常规周期,但想要LINQ。

    for (var day = start.Date; day.Date <= end.Date; day = day.AddDays(1))
    {
        if (day.DayOfWeek == DayOfWeek.Monday)
        {
            if (day.AddDays(6) < end.Date)
                result.Add(Tuple.Create(day.Date, day.AddDays(6).Date));
        }
    }
    

    如果像从美国那样从星期日开始的一周,也可以包含文化信息。

2 个答案:

答案 0 :(得分:3)

它很粗糙......但尝试这样的事情:

DateTime start = DateTime.Parse("13/09/16");
DateTime end = DateTime.Parse("5/10/16");

CultureInfo culture = Thread.CurrentThread.CurrentCulture;

Enumerable.Range(0, (end - start).Days)
    .Where(x => start.AddDays(x).DayOfWeek == culture.DateTimeFormat.FirstDayOfWeek)
    .Select(x => new Tuple<DateTime, DateTime>(start.AddDays(x), start.AddDays(x + 6)))
    .Where(x => x.Item2 < end);

这将枚举为:

| index |  first  |  second |
-----------------------------
|   0   | 19/09/16| 25/09/16|
|   1   | 26/09/16| 2/10/16 |

答案 1 :(得分:1)

给定日期,您可以通过从日期的星期几减去星期的第一天来确定星期开始的日期。然后你需要处理负数,如果一周的第一天是星期一(1),而日期的星期几是星期日(0),那就是0 - 1 = -1而不是6.这是一个函数。的是:

int GetDayOfWeekOffset(DateTime date, CultureInfo cultureInfo) {
  return ((int) (date.DayOfWeek - cultureInfo.DateTimeFormat.FirstDayOfWeek) + 7)%7;
}

因此,如果一周的第一天(由CultureInfo确定)是星期一,则该函数将在星期一,星期二,......,星期日返回0,1,...,6。如果一周的第一天是星期日,则它将在星期日,星期一,......星期六返回0,1,...,6。

您可以减去该函数返回的天数,以获得在该周的某个日期开始的一周开始的日期:

var firstWeekStart = startDate.AddDays(-GetDayOfWeekOffset(startDate, cultureInfo));
var lastWeekStart = endDate.AddDays(-GetDayOfWeekOffset(endDate, cultureInfo));

这两个日期可用于生成所需的列表:

var weekCount = (int) (lastWeekStart - firstWeekStart).TotalDays/7 + 1;
var weeks = Enumerable
  .Range(0, weekCount)
  .Select(week => firstWeekStart.AddDays(7*week))
  .Where(weekStart => startDate <= weekStart && weekStart.AddDays(6) <= endDate)
  .Select(weekStart => Tuple.Create(weekStart, weekStart.AddDays(6)))
  .ToList();

请注意Where子句,该子句确保仅包括由startDateendDate确定的日期范围内的几周。

与Scott提供的答案相比,这种方法更“有效”,因为隐式foreach循环枚举了数周而非数天(因此发烧迭代次数高达7次)。然而,只要你不必创建一个很长的周列表,“效率”可能并不重要。