Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何按周分组日期?_C#_Linq_Grouping - Fatal编程技术网

C# 如何按周分组日期?

C# 如何按周分组日期?,c#,linq,grouping,C#,Linq,Grouping,我正在为我正在创建的定制应用程序编写一个Excel导出器,我对C#中的LINQ分组有一个问题 基本上,这个新的Excel exporter类有两个日期。然后,该类检索此日期范围内的所有委托 作为导出程序的一部分,我需要能够将日期分组为周,并获取该周的值。因此,例如,如果给我2011年12月7日和2011年12月22日(dd/MM/yyyy格式),我需要将它们之间的所有托运货物分组为周(每周从周日开始)。使用上述日期的理想结果是 Week 1: (consignments between 04/1

我正在为我正在创建的定制应用程序编写一个Excel导出器,我对C#中的LINQ分组有一个问题

基本上,这个新的Excel exporter类有两个日期。然后,该类检索此日期范围内的所有委托

作为导出程序的一部分,我需要能够将日期分组为周,并获取该周的值。因此,例如,如果给我2011年12月7日和2011年12月22日(dd/MM/yyyy格式),我需要将它们之间的所有托运货物分组为周(每周从周日开始)。使用上述日期的理想结果是

Week 1: (consignments between 04/12/2011 and 10/12/2011) 
Week 2: (consignments between 11/12/2011 and 17/12/2011) 
Week 3: (consignments between 18/11/2011 and 24/12/2011)

有什么想法吗?

这里的基本问题是如何将一个
DateTime
实例投影到一周的年值中。这可以通过调用来完成。因此,定义投影:

Func<DateTime, int> weekProjector = 
    d => CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(
         d,
         CalendarWeekRule.FirstFourDayWeek,
         DayOfWeek.Sunday);

如果您还想将输出限制为两个特定日期之间的一致性,只需添加一个适当的
where
子句;分组逻辑没有改变。

虽然我不同意尊敬的回答者的观点,但我认为这里接受的答案是错误的,这从根本上讲不是预测一周的年值的问题

GetWeekOfYear()的概念通常是根据约定的标准为一年中的周分配索引值。我相信发问者所要求的那样,把日期分成七天一组是不合适的

不仅建议使用GetWeekOfYear()会导致在许多年结束时少于七天的组,更糟糕的是,GetWeekOfYear()支持的各种标准通常会将一年的第一天分配到上一年的最后一周,而GetWeekOfYear()则会结果仅包含整数周索引,不引用相关年份,按
new{year=date.year,weekproject(date)}
date.year+“-”+weekproject(date)分组
在提问者的一年中,2011年1月1日与圣诞节一起分组,直到同年12个月后的除夕

因此,我认为最初的问题基本上不是预测一周的年值,而是预测一周的所有时间值,你可能会说,“周开始y/m/d”,因此分组只需要在一周的第一天完成,即(假设你乐意默认为周日),简单地说:


除了Jon的回答之外,你还可以得到一周中第一天的日期,然后按该日期分组

获取一周中第一天的日期。 您可以使用以下代码:

public static class DateTimeExtensions
{
    public static DateTime StartOfWeek(this DateTime dt, DayOfWeek startOfWeek)
    {
        int diff = dt.DayOfWeek - startOfWeek;
        if (diff < 0)
        {
            diff += 7;
        }
        return dt.AddDays(-1 * diff).Date;
    }
}
我试着这样做(而且成功了:)

@foreach(变量年在_dateRange.GroupBy(y=>y.Year))中)
{
@几年,钥匙

foreach(年内的var月数。GroupBy(m=>m.Month)) { @CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(months.Key)

foreach(月内的var周数。GroupBy(w=>w.AddDays(-(int)w.DayOfWeek))) { @周。键。ToString(“dd-MMM-yy”)

} } }
我注意到OP在理想输出中有第1周、第2周等。这些不是一年中的一周,而是基于托运日期显示的一周的“索引”。基于已经提供的一些其他答案,以下是我的解决方案:

void DoExample()
{
    //Load some sample data
    var range = new List<DateTime>();
    var curDate = DateTime.ParseExact("07/12/2011", "dd/MM/yyyy", System.Globalization.CultureInfo.InvariantCulture);
    var maxDate = DateTime.ParseExact("22/12/2011", "dd/MM/yyyy", System.Globalization.CultureInfo.InvariantCulture);
    while(curDate < maxDate)
    {
        range.Add(curDate);
        curDate = curDate.AddDays(1);
    }
    
    //Run the method to get the consignments
    var c = GetConsignments(range, DayOfWeek.Sunday);

    //Output to match OP's "ideal" specs
    foreach(var v in c)
    {
        Console.WriteLine($"Week {v.EntryIndex + 1} (number {v.WeekOfYear} in year): (consignments between {v.RangeStart:dd/MM/yyyy} and {v.RangeEnd:dd/MM/yyyy}). Actual date range is {v.RangeStart:dd/MM/yyyy}-{v.RangeEnd:dd/MM/yyyy} ({(v.FullWeek ? "Full" : "Partial")} week)");
    }

    //Most other answers place a lot of value on the week of the year, so this would include that.
    // Also includes the actual date range contained in the set and whether all dates in that week are present
    foreach (var v in c)
    {
        Console.WriteLine($"Week {v.EntryIndex + 1} (number {v.WeekOfYear} in year): (consignments between {v.RangeStart} and {v.RangeEnd})");
    }
}

//Note that this lets us pass in what day of the week is the start.
// Not part of OP's requirements, but provides added flexibility
public List<ConsignmentRange> GetConsignments(IEnumerable<DateTime>consignments, DayOfWeek startOfWeek=DayOfWeek.Sunday)
{
    return consignments
            .OrderBy(v => v)
            .GroupBy(v => v.AddDays(-(int)((7 - (int)startOfWeek) + (int)v.DayOfWeek) % 7))
            .Select((v, idx) => new ConsignmentRange
              {
                //These are part of the OP's requirement
                EntryIndex = idx,
                RangeStart = v.Key, // part of requirement
                RangeEnd = v.Key.AddDays(6),  // part of requirement

                //These are added as potentially useful
                WeekOfYear = CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(
                             v.Key, CalendarWeekRule.FirstFourDayWeek, startOfWeek),
                FirstDate = v.Min(),
                LastDate = v.Max(),
                FullWeek = (v.Distinct().Count() == 7)
              }
            )
            .ToList();
}

我提出这个问题,因为我已经有了与公认答案非常相似的代码。我不喜欢它的原因和你说的完全一样。这段代码更简单,在划分日期方面做得更好。谢谢此外,您可以使用一周中不同的一天(如周一)进行分段,只需将该天添加到此结果中即可。我修改了答案中的建议(顺便说一句,很棒的答案),将日期时间“捕捉”到最近的时段<代码>按日期分组.AddDays(((int)date.DayOfWeek)<4?((int)date.DayOfWeek):((int)date.DayOfWeek+7))如果您有更多数据,请执行问题
public static class DateTimeExtensions
{
    public static DateTime StartOfWeek(this DateTime dt, DayOfWeek startOfWeek)
    {
        int diff = dt.DayOfWeek - startOfWeek;
        if (diff < 0)
        {
            diff += 7;
        }
        return dt.AddDays(-1 * diff).Date;
    }
}
var consignmentsByWeek = from con in consignments
                         group con by con.Datedate.StartOfWeek(DayOfWeek.Monday);
@foreach (var years in _dateRange.GroupBy(y => y.Year))
{
    <p>@years.Key</p>
    foreach (var months in years.GroupBy(m => m.Month))
    {
        <p>@CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(months.Key)</p>
        foreach (var weeks in months.GroupBy(w => w.AddDays(-(int)w.DayOfWeek)))
        {
            <p>@weeks.Key.ToString("dd-MMM-yy")</p>
        }
    }
}
void DoExample()
{
    //Load some sample data
    var range = new List<DateTime>();
    var curDate = DateTime.ParseExact("07/12/2011", "dd/MM/yyyy", System.Globalization.CultureInfo.InvariantCulture);
    var maxDate = DateTime.ParseExact("22/12/2011", "dd/MM/yyyy", System.Globalization.CultureInfo.InvariantCulture);
    while(curDate < maxDate)
    {
        range.Add(curDate);
        curDate = curDate.AddDays(1);
    }
    
    //Run the method to get the consignments
    var c = GetConsignments(range, DayOfWeek.Sunday);

    //Output to match OP's "ideal" specs
    foreach(var v in c)
    {
        Console.WriteLine($"Week {v.EntryIndex + 1} (number {v.WeekOfYear} in year): (consignments between {v.RangeStart:dd/MM/yyyy} and {v.RangeEnd:dd/MM/yyyy}). Actual date range is {v.RangeStart:dd/MM/yyyy}-{v.RangeEnd:dd/MM/yyyy} ({(v.FullWeek ? "Full" : "Partial")} week)");
    }

    //Most other answers place a lot of value on the week of the year, so this would include that.
    // Also includes the actual date range contained in the set and whether all dates in that week are present
    foreach (var v in c)
    {
        Console.WriteLine($"Week {v.EntryIndex + 1} (number {v.WeekOfYear} in year): (consignments between {v.RangeStart} and {v.RangeEnd})");
    }
}

//Note that this lets us pass in what day of the week is the start.
// Not part of OP's requirements, but provides added flexibility
public List<ConsignmentRange> GetConsignments(IEnumerable<DateTime>consignments, DayOfWeek startOfWeek=DayOfWeek.Sunday)
{
    return consignments
            .OrderBy(v => v)
            .GroupBy(v => v.AddDays(-(int)((7 - (int)startOfWeek) + (int)v.DayOfWeek) % 7))
            .Select((v, idx) => new ConsignmentRange
              {
                //These are part of the OP's requirement
                EntryIndex = idx,
                RangeStart = v.Key, // part of requirement
                RangeEnd = v.Key.AddDays(6),  // part of requirement

                //These are added as potentially useful
                WeekOfYear = CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(
                             v.Key, CalendarWeekRule.FirstFourDayWeek, startOfWeek),
                FirstDate = v.Min(),
                LastDate = v.Max(),
                FullWeek = (v.Distinct().Count() == 7)
              }
            )
            .ToList();
}
public class ConsignmentRange
{
    public int EntryIndex;
    public int WeekOfYear;
    public bool FullWeek;
    public DateTime FirstDate;
    public DateTime LastDate;
    public DateTime RangeStart;
    public DateTime RangeEnd;
}