c# - 获取给定时间间隔和步长的日期范围

标签 c# linq

编辑 看起来创建一个按分钟保存 DateTimes 的表最有意义。 100 年的分钟数约为 5200 万行。由 Ticks 索引应该使查询运行得非常快。现在变成了

感谢大家的反馈!

我有一个名为 Recurrence 的类,如下所示:

public class Recurrence
{
    public int Id { get; protected set; }
    public DateTime StartDate { get; protected set; }
    public DateTime? EndDate { get; protected set; }
    public long? RecurrenceInterval { get; protected set; }

}

它是一个 Entity Framework POCO类。对于这个类,我想用标准查询运算符做两件事。 (以便查询完全在服务器端运行)。

首先,我想创建一个查询,返回从开始日期到结束日期的所有日期(包括给定的重复间隔)。迭代功能简单

for(i=StartDate.Ticks; i<=EndDate.Ticks; i+=RecurrenceInterval)
{
  yield return new DateTime(i);
}

Enumerable.Range() 是一个选项,但没有长版本的 Range。我认为我在这里唯一的选择是聚合,但我仍然不太擅长该功能。

最后,一旦我的查询开始工作,我想从那里返回一个时间窗口内的值,即在不同的开始日期和结束日期之间。使用 SkipWhile/TakeWhile 很容易做到这一点。

如果 DateTime.Ticks 是一个 int,我可以这样做

from recurrence in Recurrences
let range =
Enumerable
  .Range(
    (int)recurrence.StartDate.Ticks,
    recurrence.EndDate.HasValue ? (int)recurrence.EndDate.Value.Ticks : (int)end.Ticks)
  .Where(i=>i-(int)recurrence.StartDate.Ticks%(int)recurrence.RecurrenceLength.Value==0)
  .SkipWhile(d => d < start.Ticks)
  .TakeWhile(d => d <= end.Ticks)
from date in range
select new ScheduledEvent { Date = new DateTime(date) };

我想我需要的是可以在 EF 查询上执行的 LongRange 实现。

最佳答案

这是产生重复点和指定子区间的交集的函数:

public class Recurrence
{
    public int Id { get; protected set; }
    public DateTime StartDate { get; protected set; }
    public DateTime? EndDate { get; protected set; }
    public long? RecurrenceInterval { get; protected set; }

    // returns the set of DateTimes within [subStart, subEnd] that are
    // of the form StartDate + k*RecurrenceInterval, where k is an Integer
    public IEnumerable<DateTime> GetBetween(DateTime subStart, DateTime subEnd)
    {            
        long stride = RecurrenceInterval ?? 1;
        if (stride < 1) 
            throw new ArgumentException("Need a positive recurrence stride");

        long realStart, realEnd;

        // figure out where we really need to start
        if (StartDate >= subStart)
            realStart = StartDate.Ticks;
        else
        {
            long rem = subStart.Ticks % stride;
            if (rem == 0)
                realStart = subStart.Ticks;
            else
                // break off the incomplete stride and add a full one
                realStart = subStart.Ticks - rem + stride;
        }
        // figure out where we really need to stop
        if (EndDate <= subEnd)
            // we know EndDate has a value. Null can't be "less than" something
            realEnd = EndDate.Value.Ticks; 
        else
        {
            long rem = subEnd.Ticks % stride;
            // break off any incomplete stride
            realEnd = subEnd.Ticks - rem;
        }
        if (realEnd < realStart)
            yield break; // the intersection is empty

        // now yield all the results in the intersection of the sets
        for (long t = realStart; t <= realEnd; t += stride)
            yield return new DateTime(t);
    }

}

关于c# - 获取给定时间间隔和步长的日期范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9084374/

相关文章:

c# - MVVM:为什么ViewModel应该对View一无所知?

c# - 请求额外 claim Owin Security

c# - LINQ 转换问题

c# - 时间表 : Retrieve data using SQL, LINQ 或类?

c# - 使用 FindLast 之类的方法时如何区分找到的 0 和默认值(int)?

c# - 身份服务器 4 : How so you include additional claims and get the value in an API controller?

c# - 使用 xamarin.android 创建自定义通知

c# - 将字典添加到另一个字典的值

c# - LINQ - 根据最后一个 child 的条件获得 parent

linq - 动态构建 Linq 查询