簡體   English   中英

獲取給定間隔和步驟的日期范圍

[英]Get a range of dates given an interval and step

編輯似乎最有意義的是創建一個表,該表按分鍾連接保存DateTimes。 100年的分鍾記錄約有5200萬行。 通過Ticks索引可以使查詢運行得非常快。 現在變成

感謝大家的反饋!

我有一個稱為遞歸的類,看起來像這樣:

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; }

}

它是一個實體框架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 static class EnumerableEx
{
    public static IEnumerable<DateTime> DateRange(DateTime startDate, DateTime endDate, TimeSpan intervall)
    {
        for (DateTime d = startDate; d <= endDate; d += intervall) {
            yield return d;
        }
    }
}

然后用

var query =
    from recurrence in Recurrences
    from date in EnumerableEx.DateRange(recurrence.StartDate,
                                        recurrence.EndDate ?? end,
                                        recurrence.RecurrenceInterval)
    select new ScheduledEvent { Date = date };

這假定RecurrenceInterval被聲明為TimeSpan並以DateTime end


編輯:您是否期望此版本限制服務器端的重復出現?

var query =
    from recurrence in Recurrences
    where
        recurrence.StartDate <= end &&
        (recurrence.EndDate != null && recurrence.EndDate.Value >= start ||
         recurrence.EndDate == null)
    from date in EnumerableEx.DateRange(
        recurrence.StartDate,
        recurrence.EndDate.HasValue && recurrence.EndDate.Value < end ? recurrence.EndDate.Value : end,
        recurrence.RecurrenceInterval)
    where (date >= start)
    select new ScheduledEvent { Date = date };

在這里,返回的重復周期已經考慮了start日期和end日期,因此不會返回過時的重復周期。 EnumerableEx.DateRange對查詢的第一部分無效。

這是產生遞歸點和指定子間隔的交點的函數:

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);
    }

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM