Linq查询求和范围内的日期

时间:2011-02-09 16:57:57

标签: c# vb.net linq datetime

尝试解决这个问题的好方法,最好是在Linq而不是循环中,这就是我现在所做的。

我希望我的产品在两个日期之间有效。

Product有许多ProductHistories,ProductHistory具有DateActive和DateInactive的值。 DateInactive可以为null,通常也是,以显示此历史记录正在进行中。历史不会重叠。

我想将startDate或ProductHistory的DateActive的最大值相加,并从endDate或ProductHistory的最小值DateInactive的总和中减去该总和(如果DateInactive没有值,则默认为endDate)。

工作示例:

获取2011 - 01 - 01(1月1日)和2011 - 02 - 01(2月1日)之间的有效活动天数

史:

Active 2010-12-25 : Inactive 2011-01-05
Active 2011-01-15 : Inactive 2011-01-20
Active 2011-01-25 : Inactive null

这应该总共16天(4 + 5 + 7)

我现在最擅长的是相当丑陋:

    Dim a As Integer = (From h In histories
            Select If(h.ActiveDate > startDate, h.ActiveDate, startDate)).Sum(Function(d) d.Ticks) / TimeSpan.TicksPerDay

    Dim b As Integer = (From h In histories
            Select If(h.InactiveDate.HasValue AndAlso h.InactiveDate < endDate, h.InactiveDate, endDate)).Sum(Function(d) d.Value.Ticks) / TimeSpan.TicksPerDay

Return b - a

有什么想法? (无论是C#还是VB都没问题,我会翻译)

1 个答案:

答案 0 :(得分:1)

这样的东西? (假设没有重叠的历史)

var numDays = product
             .ProductHistories
             .Where(ph => ph.Active >= start && ph.Active < end)
             .Sum(ph => ph.Active
                          .Subtract(end > ph.Inactive ? ph.Inactive.Value : end)
                          .Duration() // because we are doing start - end
                          .Days);
  1. 仅考虑日期范围内开始的历史记录。
  2. 对于每个历史记录,将时间跨度构建为活动日期与非活动日期和结束日期的早期之间的差值。
  3. 总结一下。
  4. 为了改善这一点,我建议:

    1. 写一个IsBetween扩展名,可以将lambda写为ph.Active.IsBetween(start, end)
    2. 将sum lambda解压缩为另一种方法,并更直观地编写它。在DateTime?上使用了一个“提升”操作符,很多人会发现这种操作非常不直观。