按日期之间的所有完整周分组- LINQ

本文关键字:LINQ 之间 日期 | 更新日期: 2023-09-27 18:07:01

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

我有一个日期周期(开始日期和结束日期)。是否有可能得到Tuple<DateTime, DateTime>或其他item_1是一周的开始日而item_2是结束日?我的意思是我终于想看List<Tuple<DateTime, DateTime>>了。

例如,我的月经是从13/09/16到5/10/16因此,我希望看到一个包含两个组的列表:

  1. 19/09/16 - 25/09/16
  2. 26/09/16 - 2/10/16

我已经为此写了一个常规循环,但想要有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));
    }
}

如果像美国那样从星期日开始一周,最好包括文化信息。

按日期之间的所有完整周分组- LINQ

很粗糙…但是试试这样做:

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),而日期的星期几是星期日(0),则需要处理负数,如0 - 1 = -1而不是6。下面是一个这样做的函数:

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

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

你可以减去函数返回的天数,得到一周开始的日期,给定一周的日期:

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次发烧迭代)。然而,只要你不需要创建一个很长的周列表,"效率"可能并不重要。