问题 检查c#中的日期范围是否是连续的?


假设我有一个用户界面,用户可以选择日期。有没有办法检查所选日期是否是连续的,例如:

4 / 4,4 / 5,4 / 6,4 / 7,4 / 8,4 / 9,4 / 10或

4 / 29,4 / 30,5 / 1,5 / 2,5 / 3

我知道我可能会遍历日期范围并检查,但是如果有一个内置方法已经检查过这个我更好奇。

关于上述情况,它们是有序的,它们可以延续到下个月。

我使用的是.NET Framework 2.0,无法使用LINQ。

关于汤姆的回答:

DateTime dtStart = new DateTime(2011,5,4);
DateTime dtEnd = new DateTime(2011,5,11);

int numberOfDaysSelected = 7; //Assume 7 days were selected.

TimeSpan ts = dtEnd - dtStart;


if(ts.Days == numberOfDaysSelected - 1)
{
Console.WriteLine("Sequential");
}
else
{
Console.WriteLine("Non-Sequential");
}

5188
2018-05-04 16:58


起源

应该 if(ts.Days == numberOfDaysSelected-1)因为你连续两天的时间跨度是一天,而不是两天。 - BrokenGlass
如果开始日期是2011年5月4日,结束日期是5/11/2011,那么实际上总共选择了8天(5 / 4,5 / 5,5 / 6,5 / 7,5 / 8 ,5 / 9,5 / 10和5/11)。你需要考虑上面评论中提到的BrokenGlass的修复。我将编辑我的答案以反映所需的“-1”。 - Tom
好的,谢谢你们俩。 - Xaisoft


答案:


我不相信有一种内置的方法来实现您想要的结果,但是如果您可以轻松地告诉最早和最晚的日期,您可以通过从最新日期减去最早的日期然后验证数量来创建新的TimeSpan。时间跨度与所选日期的数量相匹配 - 1。


11
2018-05-04 17:08



+1除非我遗漏了一些东西,否则这是一个很好的解决方案 - Aaron Anodide
+1,因为我相信这是最好的解决方案。但请注意,它要求您的日期列表中没有重复项。 - JSBձոգչ
这是一个简洁的解决方案,它们不可能是重复的。 - Xaisoft
-1因为它假设日期日期列表既是唯一的又是有序的。 - Nicholas Carey
@Nicholas,在我的情况下,日期是有序和独特的。 - Xaisoft


您没有告诉我们订购的日期。

你没有告诉我们他们是否可能会超过一个月的边界

30, 31, 1.

我会假设有序,我会假设他们不会超过一个月的边界(因为你的例子是有序的,它不会超过一个月的边界)。

然后你可以说

public bool IsSequential(this IEnumerable<DateTime> sequence) {
    Contract.Requires(sequence != null);
    var e = sequence.GetEnumerator();
    if(!e.MoveNext()) {
        // empty sequence is sequential
        return true;
    }
    int previous = e.Current.Date;
    while(e.MoveNext()) {
        if(e.Current.Date != previous.AddDays(1)) {
            return false;
        }      
        previous = e.Current.Date;
    }
    return true;
}

请注意,此解决方案只需要执行一次序列。如果您没有有序的序列,或者如果您允许超过一个月的边界,则解决方案会更复杂。


2
2018-05-04 17:03



更新的帖子。他们是有序的,他们可以翻身。我用2个场景更新了帖子。 - Xaisoft
@Xaisoft:他们是作为实例输入的 DateTime? - jason
-1,因为实现这个 int 而不是 DateTime 滥用框架并施加不必要的约束。我认为汤姆有更好的答案。 - JSBձոգչ
@Jason,是的,他们是DateTime实例。在你的代码中,什么是Contract.Requires? - Xaisoft
@JSBangs,在这种情况下是否重要,你会找到一个不是int的日子。 - Xaisoft


没有内置但你可以使用Linq轻松构建一个:

List<DateTime> timeList = new List<DateTime>();
//populate list..
bool isSequential = timeList.Zip(timeList.Skip(1), 
                                 (a, b) => b.Date == a.Date.AddDays(1))
                            .All(x => x);

编辑 - 误解的问题首先是指时间上升而不是顺序 - 修正了。


1
2018-05-04 17:04



你介意解释这段代码吗? - Xaisoft
一个问题:我仍在使用.NET 2.0,无法使用LINQ。 - Xaisoft
@Xaisoft:然后忽略这个解决方案,它只适用于.NET 4 - @ Tom的方法应该有效。 - BrokenGlass


使用Linq的扩展方法:

public static bool IsContiguous(this IEnumerable<DateTime> dates)
{
    var startDate = dates.FirstOrDefault();

    if (startDate == null)
        return true;

    //.All() doesn't provide an indexed overload :(
    return dates
        .Select((d, i) => new { Date = d, Index = i })
        .All(d => (d.Date - startDate).Days == d.Index);
}

测试它:

List<DateTime> contiguousDates = new List<DateTime>
{
    new DateTime(2011, 05, 05),
    new DateTime(2011, 05, 06),
    new DateTime(2011, 05, 07),
};
List<DateTime> randomDates = new List<DateTime>
{
    new DateTime(2011, 05, 05),
    new DateTime(2011, 05, 07),
    new DateTime(2011, 05, 08),
};

Console.WriteLine(contiguousDates.IsContiguous());
Console.WriteLine(randomDates.IsContiguous());

返回

True
False

编辑

.NET 2般的答案:

public static bool CheckContiguousDates(DateTime[] dates)
{
    //assuming not null and count > 0
    var startDate = dates[0];

    for (int i = 0; i < dates.Length; i++)
    {
        if ((dates[i] - startDate).Days != i)
            return false;
    }
    return true;
}

1
2018-05-04 17:20



仍然在.NET 2上,不能使用LINQ。 - Xaisoft


你可以使用 TimeGapCalculator 的 .NET的时间段库 找出多个时间段之间的差距(独立于顺序,计数和重叠):

// ----------------------------------------------------------------------
public void SequentialPeriodsDemo()
{
  // sequential
  ITimePeriodCollection periods = new TimePeriodCollection();
  periods.Add( new Days( new DateTime( 2011, 5, 4 ), 2 ) );
  periods.Add( new Days( new DateTime( 2011, 5, 6 ), 3 ) );
  Console.WriteLine( "Sequential: " + IsSequential( periods ) );

  periods.Add( new Days( new DateTime( 2011, 5, 10 ), 1 ) );
  Console.WriteLine( "Sequential: " + IsSequential( periods ) );
} // SequentialPeriodsDemo

// --------------------------------------------------------------------
public bool IsSequential( ITimePeriodCollection periods, ITimePeriod limits = null )
{
  return new TimeGapCalculator<TimeRange>( 
    new TimeCalendar() ).GetGaps( periods, limits ).Count == 0;
} // IsSequential

0
2017-10-01 14:08