检测重叠周期的算法

J4N*_*J4N 379 .net c# algorithm time datetime

我要检测两个时间段是否重叠.
每个期间都有开始日期和结束日期.
我需要检测我的第一个时间段(A)是否与另一个时间段(B/C)重叠.
在我的情况下,如果B的开头等于A的结尾,它们不重叠(反过来)
我发现以下情况:

在此输入图像描述

所以实际上我这样做是这样的:

tStartA < tStartB && tStartB < tEndA //For case 1
OR
tStartA < tEndB && tEndB <= tEndA //For case 2
OR
tStartB < tStartA  && tEndB > tEndA //For case 3
Run Code Online (Sandbox Code Playgroud)

(案例4在案例1或案例2中被记入帐户)

有效,但似乎效率不高.

所以,首先在c#中有一个现有的类可以对此进行建模(一个时间段),类似于时间跨度,但具有固定的开始日期.

其次:是否已经有ac#代码(比如在DateTime类中)可以处理这个问题?

第三:如果不是,那么你最快速地进行这种比较的方法是什么?

Raw*_*ing 664

只需检查两个时间段是否重叠:

bool overlap = a.start < b.end && b.start < a.end;
Run Code Online (Sandbox Code Playgroud)

或者在你的代码中:

bool overlap = tStartA < tEndB && tStartB < tEndA;
Run Code Online (Sandbox Code Playgroud)

(使用<=的,而不是<如果你改变主意不想说两个时段,只是互相接触重叠.)

  • 美丽!它回答"可能有两个人见过面","是的,如果两个人都在另一个人死前".当你表达相反的情况时,这种作用的原因**变得清晰了:"如果在另一个人出生之前死亡,那就没有了." 实际上,仅测试案例5:`overlap =!(a.start> b.end || b.start> a.end)` (60认同)
  • @ J4N第一次我必须这样做,我写了像你的代码,直到有人指出这一点.只是传递它:) (8认同)
  • 我不知道这涵盖了所有场景. (7认同)
  • @Rawling我只是不明白但是它有效.你是对的.我最深切的尊重. (4认同)
  • @doker它是对称的.如果你交换`a`和`b`你会得到相同的语句,只是在`&&`的任何一侧切换. (3认同)
  • @doker 想出了另一种方式来解释这种惊人的简化:请注意,在情况 1-4 中 **所有 tStarts 都小于所有 tEnds**。所以存在一个时间在所有 tStarts 之后和所有 tEnds 之前。IE重叠。如果您可以假设每个时期都正确地订购了自己(它自己的 tStart &lt; tEnd),那么任务就简化为“交叉检查”。 (2认同)
  • @DanB如果两个范围相同,你得到的是'a.start <a.end && a.start <a.end`,这是非常真实的.如果你交换`a`和`b`你会得到`b.start <a.end && a.start <b.end`,它只是将参数切换为`&&`. (2认同)
  • 它美丽而优雅 (2认同)
  • 当我编写第一个商业应用程序时,这个答案对我很有帮助。两年后,我需要解决类似的问题 - 阅读这个答案感觉就像回到家一样! (2认同)

Ren*_*ink 44

有一个很棒的图书馆,对CodeProject有很好的评价:http://www.codeproject.com/Articles/168662/Time-Period-Library-for-NET

那个库在重叠,交叉它们等方面做了很多工作.复制/粘贴它们太大了,但是我会看到哪些特定的部分对你有用.


Ale*_*exH 18

您可以创建可重用的Range模式类:

public class Range<T> where T : IComparable
{
    readonly T min;
    readonly T max;

    public Range(T min, T max)
    {
        this.min = min;
        this.max = max;
    }

    public bool IsOverlapped(Range<T> other)
    {
        return Min.CompareTo(other.Max) < 0 && other.Min.CompareTo(Max) < 0;
    }

    public T Min { get { return min; } }
    public T Max { get { return max; } }
}
Run Code Online (Sandbox Code Playgroud)

您可以添加合并范围,交叉点等所需的所有方法......

  • 很好的答案,但是比较应该是 return Min.CompareTo(other.Max) &lt;= 0 &amp;&amp; other.Min.CompareTo(Max) &lt;= 0; (2认同)

you*_*mri 10

我正在建立一个预订系统并找到了这个页面.我只对范围交叉感兴趣,所以我构建了这个结构; 使用DateTime范围就足够了.

您可以检查交叉点并检查特定日期是否在范围内,并获取交叉点类型和最重要的:您可以获得相交的范围.

public struct DateTimeRange
{

    #region Construction
    public DateTimeRange(DateTime start, DateTime end) {
        if (start>end) {
            throw new Exception("Invalid range edges.");
        }
        _Start = start;
        _End = end;
    }
    #endregion

    #region Properties
    private DateTime _Start;

    public DateTime Start {
        get { return _Start; }
        private set { _Start = value; }
    }
    private DateTime _End;

    public DateTime End {
        get { return _End; }
        private set { _End = value; }
    }
    #endregion

    #region Operators
    public static bool operator ==(DateTimeRange range1, DateTimeRange range2) {
        return range1.Equals(range2);
    }

    public static bool operator !=(DateTimeRange range1, DateTimeRange range2) {
        return !(range1 == range2);
    }
    public override bool Equals(object obj) {
        if (obj is DateTimeRange) {
            var range1 = this;
            var range2 = (DateTimeRange)obj;
            return range1.Start == range2.Start && range1.End == range2.End;
        }
        return base.Equals(obj);
    }
    public override int GetHashCode() {
        return base.GetHashCode();
    }
    #endregion

    #region Querying
    public bool Intersects(DateTimeRange range) {
        var type = GetIntersectionType(range);
        return type != IntersectionType.None;
    }
    public bool IsInRange(DateTime date) {
        return (date >= this.Start) && (date <= this.End);
    }
    public IntersectionType GetIntersectionType(DateTimeRange range) {
        if (this == range) {
            return IntersectionType.RangesEqauled;
        }
        else if (IsInRange(range.Start) && IsInRange(range.End)) {
            return IntersectionType.ContainedInRange;
        }
        else if (IsInRange(range.Start)) {
            return IntersectionType.StartsInRange;
        }
        else if (IsInRange(range.End)) {
            return IntersectionType.EndsInRange;
        }
        else if (range.IsInRange(this.Start) && range.IsInRange(this.End)) {
            return IntersectionType.ContainsRange;
        }
        return IntersectionType.None;
    }
    public DateTimeRange GetIntersection(DateTimeRange range) {
        var type = this.GetIntersectionType(range);
        if (type == IntersectionType.RangesEqauled || type==IntersectionType.ContainedInRange) {
            return range;
        }
        else if (type == IntersectionType.StartsInRange) {
            return new DateTimeRange(range.Start, this.End);
        }
        else if (type == IntersectionType.EndsInRange) {
            return new DateTimeRange(this.Start, range.End);
        }
        else if (type == IntersectionType.ContainsRange) {
            return this;
        }
        else {
            return default(DateTimeRange);
        }
    }
    #endregion


    public override string ToString() {
        return Start.ToString() + " - " + End.ToString();
    }
}
public enum IntersectionType
{
    /// <summary>
    /// No Intersection
    /// </summary>
    None = -1,
    /// <summary>
    /// Given range ends inside the range
    /// </summary>
    EndsInRange,
    /// <summary>
    /// Given range starts inside the range
    /// </summary>
    StartsInRange,
    /// <summary>
    /// Both ranges are equaled
    /// </summary>
    RangesEqauled,
    /// <summary>
    /// Given range contained in the range
    /// </summary>
    ContainedInRange,
    /// <summary>
    /// Given range contains the range
    /// </summary>
    ContainsRange,
}
Run Code Online (Sandbox Code Playgroud)


lis*_*ous 7

这是我的解决方案:

public static bool OverlappingPeriods(DateTime aStart, DateTime aEnd,
                                      DateTime bStart, DateTime bEnd)
{
    if (aStart > aEnd)
        throw new ArgumentException("A start can not be after its end.");

    if(bStart > bEnd)
        throw new ArgumentException("B start can not be after its end.");

    return !((aEnd < bStart && aStart < bStart) ||
                (bEnd < aStart && bStart < aStart));
}
Run Code Online (Sandbox Code Playgroud)

我对它进行了单元测试,覆盖率为 100%。


Dus*_*jik 5

此代码检查两个间隔是否重叠。

---------|---|
---|---|                > FALSE
xxxxxxxxxxxxxxxxxxxxxxxxx
-------|---|
---|---|                > FALSE
xxxxxxxxxxxxxxxxxxxxxxxxx
------|---|
---|---|                > TRUE
xxxxxxxxxxxxxxxxxxxxxxxxx
---|---|
---|--|                 > TRUE
xxxxxxxxxxxxxxxxxxxxxxxxx
----|---|
---|-----|              > TRUE
xxxxxxxxxxxxxxxxxxxxxxxxx
---|---|
----|-|                 > TRUE
xxxxxxxxxxxxxxxxxxxxxxxxx
---|---|
----|--|                > TRUE
xxxxxxxxxxxxxxxxxxxxxxxxx
---|---|
---|---|                > TRUE
xxxxxxxxxxxxxxxxxxxxxxxxx
---|---|
----|---|               > TRUE
xxxxxxxxxxxxxxxxxxxxxxxxx
---|---|
-------|---|            > TRUE
xxxxxxxxxxxxxxxxxxxxxxxxx
---|---|
--------|---|           > TRUE
Run Code Online (Sandbox Code Playgroud)

算法:

x1 < y2
and
x2 > y1
Run Code Online (Sandbox Code Playgroud)

示例12:00-12:30与12:30 13:00不重叠