【问题标题】:Cleaner way of filtering datetime by week in C#在 C# 中按周过滤日期时间的更简洁方法
【发布时间】:2017-07-14 15:30:38
【问题描述】:

我有一个带有日期的大型记录数据库。当用户选择 MTD 时,程序从今天开始计算每 7 天的记录数(不使用当月的周数,所以我不能使用 .Day 或 .GetWeekOfMonth)。现在它看起来像这样:

    if (options.timeRange == "MTD")
{
    if (x.close_dt.Value.Date < DateTime.Today.AddMonths(-1))
    {
        complete = true;
    }
    if (DateTime.Today.AddMonths(-1).Date <= x.close_dt.Value.Date && x.close_dt.Value.Date <= DateTime.Today)
    {
        if (DateTime.Today.AddDays(-6).Date <= x.close_dt.Value.Date && x.close_dt.Value.Date <= DateTime.Today.Date)
        {
            chartObj.weeks[0]++;
        }
        else if (DateTime.Today.AddDays(-13).Date <= x.close_dt.Value.Date && x.close_dt.Value.Date <= DateTime.Today.AddDays(-7).Date)
        {
            chartObj.weeks[1]++;
        }
        else if (DateTime.Today.AddDays(-20).Date <= x.close_dt.Value.Date && x.close_dt.Value.Date <= DateTime.Today.AddDays(-14).Date)
        {
            chartObj.weeks[2]++;
        }
        else if (DateTime.Today.AddDays(-27).Date <= x.close_dt.Value.Date && x.close_dt.Value.Date <= DateTime.Today.AddDays(-21).Date)
        {
            chartObj.weeks[3]++;
        }
    }
}

感谢您的帮助

【问题讨论】:

  • 这个函数到底应该做什么?如果是 MTD,为什么要减去一个月?
  • @maccettura 这是在 foreach 循环中。 x 是当前记录,记录按日期降序排序。该函数计算每个“周”中的记录数。周是前 7 天的跨度。如果记录超过一个月,则 x.close_dt.Value.Date
  • 我还是不明白你的要求。如果“周”被定义为从今天开始的前 7 天,那么我们什么时候停止计算“周”?假设今天是 7/11/17,前一周是 7/4-7/11,但前一周将下降到 6 月。那个“周”应该是部分的吗?是否应该进入六月才能完成“一周”?如果是这样,则更改 MTD(月至今)的含义。
  • 另外,您上面的代码似乎假设一个月是 31 天。 30 个月呢?二月呢?
  • 我意识到我没有正确使用 MTD。我应该说“前 4 周”。是的,它会持续到六月。最后的 28-31 if 是我正在尝试的其他东西的残余,所以我摆脱了它。

标签: c# asp.net asp.net-mvc visual-studio datetime


【解决方案1】:

我仍然不确定我是否正确地关注了您,但如果您只想检查今天日期的前 4 周并增加每个“周”计数,您可以大大简化您的代码。

首先,通过不重复常见代码来保持代码干燥:

private static bool DateInRange(DateTime date, DateTime minDate, DateTime maxDate)
{
    return date.Date > minDate.Date && date.Date <= maxDate.Date;
}

然后将您的 foreach 循环更改为:

//Store todays date in a variable so you don't grab it every time 
//(it changes every "tick" you know)
var todaysDate = DateTime.Now;

foreach(var date in sampleDates)
{
    //Date is out of our 4 "week" range, skip to next loop
    if(date.Date < todaysDate.AddDays(-28).Date || date.Date > todaysDate.Date)
    {
        continue;
    }

    //Using simple math we skip a lot of unnecessary code
    //This loop runs 4 times
    //-7 - 0
    //-14 - -7
    //-21 - -14
    //-28 - -21
    for(int i = 0; i < 4; i++)
    {            
        if(DateInRange(date, todaysDate.AddDays((i + 1) * -7), todaysDate.AddDays(-7 * i)))
        {
            //Increment our "week's" counter
            weekCount[i]++;
        }
    }                       
}

小提琴here

【讨论】:

  • @PatrickD。确保您对其进行了一些测试和调试,我只是快速将它放在一起。
【解决方案2】:

您可以通过Enumerable.RangeToDictionary 轻松做到这一点:

var recordsByWeek = Enumerable.Range(0, 4).ToDictionary(i => i + 1, i =>
{
    var start = DateTime.Today.AddDays(7 * i);
    var end = start.AddDays(7);
    return records.Where(r => start <= r.Date && r.Date < end).ToList();
});

然后,您可以简单地执行以下操作:

Week 1 Record Count: @recordsByWeek[1].Count;

更新

我最初错过了关于它是之前周的部分。代码基本相同,但略有修改。我将保留原件进行比较,以防万一互联网上的某个人偶然发现了这个并且实际上需要它。

var recordsByWeek = Enumerable.Range(0, 4).Reverse().ToDictionary(i => 4 - i, i =>
{
    var end = DateTime.Today.AddDays(-7 * i);
    var start = end.AddDays(-7);
    return records.Where(r => start <= r.Date && r.Date < end).ToList();
});

本质上,您只需反转可枚举,因此它是 3, 2, 1, 0 而不是 0, 1, 2, 3。然后,要获得周数,从4 中减去i,得到1, 2, 3, 4。最后startend的计算基本上是颠倒过来的,所以我们先用可枚举的值确定end,然后再减去7天得到start

哦,还有一件事,这实际上是今天的独家。如果您还需要包括今天,这样第 4 周就会从今天开始计算记录,那么您只需在计算 end 时添加额外的一天:

var end = DateTime.Today.AddDays(-7 * i + 1);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-07-03
    • 2014-05-27
    • 2023-03-16
    • 1970-01-01
    • 2016-12-17
    • 2013-10-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多