Linq集团按月/年分为过去12个月的空月

时间:2014-11-09 19:12:21

标签: c# .net linq

如何获取此查询以获取过去12个月的每月统计数据?我不想对范围进行硬编码,我想使用当前日期DateTime.Now并获取过去12个月的所有数据。我试图避免将日历表添加到数据库,只使用LINQ

有些月份可能没有任何数据,但我仍然需要0的数量。

例如。如果我的数据包含

Date     Count
12/2/2013, 4
10/1/2014, 1
11/5/2014, 6

结果应使用当前日期2014年11月9日

11/2013, 0
12/1013, 4
 1/2014, 0
 2/2014, 0
 3/2014, 0
 4/2014, 0
 5/2014, 0
 6/2014, 0
 7/2014, 0
 8/2014, 0
 9/2014, 0
10/2014, 1
11/2014, 6

我无法让它发挥作用。我认为这是我使用Range的方式,但我不确定。

TimeSpan ts = new TimeSpan(365, 0, 0, 0);
DateTime yearAgo = DateTime.Now.Subtract(ts);

var changesPerYearAndMonth =
    from year in Enumerable.Range(yearAgo.Year, 1)
    from month in Enumerable.Range(1, 12)
    let key = new { Year = year, Month = month }
    join revision in list on key
          equals new { revision.LocalTimeStamp.Year, 
                       revision.LocalTimeStamp.Month } into g
    select new { GroupCriteria = key, Count = g.Count() };

我已将此链接的答案修改为起点。 Linq: group by year and month, and manage empty months

我刚发现这篇文章是同一个问题,但没有答案 Linq - group by datetime for previous 12 months - include empty months

4 个答案:

答案 0 :(得分:3)

要过去十二个月,请使用

var now = DateTime.Now;
var months = Enumerable.Range(-12, 12)
    .Select(x => new { 
        year = now.AddMonths(x).Year, 
        month = now.AddMonths(x).Month });

为了安全起见,你应该先行动,现在'到月初,以避免AddMonth的任何月末影响。

var now = DateTime.Now;
now = now.Date.AddDays(1-now.Day);

完整示例: -

 var list = new [] {
            new { LocalTimeStamp = DateTime.Parse("12/2/2013"), count = 4},
            new { LocalTimeStamp = DateTime.Parse("10/1/2014"), count = 1 },
            new { LocalTimeStamp = DateTime.Parse("11/5/2014"), count = 6}
        };

        var now = DateTime.Now;
        now = now.Date.AddDays(1-now.Day);
        var months = Enumerable.Range(-12, 13)
            .Select(x => new { 
                year = now.AddMonths(x).Year, 
                month = now.AddMonths(x).Month });

        var changesPerYearAndMonth =
            months.GroupJoin(list, 
                m => new {month = m.month, year = m.year}, 
                revision => new { month = revision.LocalTimeStamp.Month,
                                  year = revision.LocalTimeStamp.Year},
                (p, g) => new {month = p.month, year = p.year, 
                               count = g.Sum(a => a.count)});


        foreach (var change in changesPerYearAndMonth)
        {
            Console.WriteLine(change.month + " " + change.year +" " + change.count);
        }

答案 1 :(得分:2)

您不需要3方式加入,只需在分组前过滤数据即可。

1)查询表达式语法

// since your list item type was not posted, anyway same access as your LocalTimeStamp property
list = new List<DateTime>();
DateTime aYearAgo = DateTime.Now.AddYears(-1);
var dateslastYear = from date in list
                 where date > aYearAgo
                 group date by new { date.Year, date.Month } into g
                 select new { GroupCriteria = g.Key, Count = g.Count() };

2)链接

dateslastYear = list.Where (d=>d>aYearAgo)
                    .GroupBy (date=>new{date.Year, date.Month });

3)如果您希望按年/月对进行分组,包括不存在的条目的记录,并且还要省略那些与加入的Enumerable.Range电话相关的年龄超过一年的对:

  var thisYearPairs = from m in Enumerable.Range(1, DateTime.Now.Month)
                      select new { Year = DateTime.Now.Year, Month = m };
  var lastYearPairs = from m in Enumerable.Range(DateTime.Now.Month, 12 - DateTime.Now.Month + 1)
                      select new { Year = DateTime.Now.Year - 1, Month = m };
  var ymOuter = from ym in thisYearPairs.Union(lastYearPairs)
                join l in list on new { ym.Year, ym.Month } equals new { l.Year, l.Month } into oj
                from p in oj.DefaultIfEmpty()
                select new { a = ym, b = p == null ? DateTime.MinValue : p };
  var ymGroup = from ym in ymOuter
                group ym by ym into g
                select new { GroupCriteria = g.Key.a, Count = g.Key.b == DateTime.MinValue ? 0 : g.Count() };

答案 2 :(得分:1)

你正在考虑去年12个月的范围,但实际上你想要过去12个月。

您可以使用Enumerable.RangeAddMonths方法执行此操作:

var changesPerYearAndMonth =
    from month in Enumerable.Range(0, 12)
    let key = new { Year = DateTime.Now.AddMonths(-month).Year, Month = DateTime.Now.AddMonths(-month).Month }
    join revision in list on key
            equals new
            {
                revision.LocalTimeStamp.Year,
                revision.LocalTimeStamp.Month
            } into g
    select new { GroupCriteria = key, Count = g.Count() };

答案 3 :(得分:0)

public int YearDiff(DateTime a, DateTime b)
{
    return (int) Math.Floor((a.Year + a.Month / 100.0 + a.Day / 10000.0) - (b.Year + b.Month / 100.0 + b.Day / 10000.0));
}