两个列表中的非重叠日期时间

时间:2018-09-04 15:12:59

标签: c# .net linq

我正在做一个个人项目,只返回我拥有的可用插槽。 我有两个列表,一个带有所有可能的日期时间槽,另一个带有所有阻止日期时间的列表。

现在我有以下代码,但是正在返回重叠的记录(这与我想要的相反)

那么,我做错了什么,最好的方法是什么?

(我搜索并且找不到与非重叠日期时间有关的任何内容)

结果应该是这样的:

  • 2018-09-01 05:00:00
  • 2018-09-02 01:30:00

    班级DateSpan {     公共DateTime StartDate;     公共DateTime EndDate;

    public DateSpan(DateTime start, DateTime end)
    {
        StartDate = start;
        EndDate = end;
    }
    
    public DateSpan(DateTime start, int duration)
    {
        StartDate = start;
        EndDate = start.AddHours(duration);
    }
    
    
    public static void Main(string[] args)
    {
        var AvailableHours = new System.Collections.Generic.List<DateSpan>();
        AvailableHours.Add(new DateSpan(new DateTime(2018, 9, 1, 5, 0, 0), 2));
        AvailableHours.Add(new DateSpan(new DateTime(2018, 9, 2, 4, 0, 0), 2));
        AvailableHours.Add(new DateSpan(new DateTime(2018, 9, 2, 5, 0, 0), 2));
        AvailableHours.Add(new DateSpan(new DateTime(2018, 9, 2, 1, 30, 0), 2));
        AvailableHours.Add(new DateSpan(new DateTime(2018, 9, 4, 5, 0, 0), 2));
    
        var BlockTimes = new System.Collections.Generic.List<DateSpan>();
        BlockTimes.Add(new DateSpan(new DateTime(2018, 9, 1, 10, 0, 0), 2));
        BlockTimes.Add(new DateSpan(new DateTime(2018, 9, 2, 5, 0, 0), 2));
        BlockTimes.Add(new DateSpan(new DateTime(2018, 9, 3, 5, 0, 0), 2));
        BlockTimes.Add(new DateSpan(new DateTime(2018, 9, 4, 4, 0, 0), 2));
    
        var e = AvailableHours.SelectMany((DateSpan x) =>
        {
            var result = new List<DateSpan>();
            foreach (var o in BlockTimes.Where(y => x.StartDate < y.StartDate && y.StartDate < x.EndDate).ToList())
            {
                result.Add(new DateSpan(new DateTime(Math.Max(x.StartDate.Ticks, o.StartDate.Ticks)), new DateTime(Math.Min(x.EndDate.Ticks, o.EndDate.Ticks))));
            }
            return result;
        });
    }
    

    }

2 个答案:

答案 0 :(得分:0)

根据对您问题的澄清,这似乎可以解决问题。它使用foreach循环而不是直接的Linq,但是对我来说,这使代码更具可读性,并且解决方案更简单:

private List<DateSpan> GetNonOverlappingTimes()
{
    var AvailableHours = new System.Collections.Generic.List<DateSpan>();
    AvailableHours.Add(new DateSpan(new DateTime(2018, 9, 1, 5, 0, 0), 2));
    AvailableHours.Add(new DateSpan(new DateTime(2018, 9, 2, 4, 0, 0), 2));
    AvailableHours.Add(new DateSpan(new DateTime(2018, 9, 2, 5, 0, 0), 2));
    AvailableHours.Add(new DateSpan(new DateTime(2018, 9, 2, 1, 30, 0), 2));
    AvailableHours.Add(new DateSpan(new DateTime(2018, 9, 4, 5, 0, 0), 2));

    var BlockTimes = new System.Collections.Generic.List<DateSpan>();
    BlockTimes.Add(new DateSpan(new DateTime(2018, 9, 1, 10, 0, 0), 2));
    BlockTimes.Add(new DateSpan(new DateTime(2018, 9, 2, 5, 0, 0), 2));
    BlockTimes.Add(new DateSpan(new DateTime(2018, 9, 3, 5, 0, 0), 2));
    BlockTimes.Add(new DateSpan(new DateTime(2018, 9, 4, 4, 0, 0), 2));

    var availableTimes = new List<DateSpan>();
    foreach (var avail in AvailableHours)
    {
        // check if there are any block times where the start date or end date is between the start date and end date of the available time
        bool isConflict = BlockTimes.Exists(bt => (bt.StartDate >= avail.StartDate && bt.StartDate < avail.EndDate) || (bt.EndDate > avail.StartDate && bt.EndDate <= avail.EndDate));

        if (!isConflict)
            availableTimes.Add(avail);
    }
    return availableTimes;
}

这给出了您期望的结果。

答案 1 :(得分:0)

DateSpan类中定义一个方法,该方法将知道如何确定两个日期跨度是否相交:

public bool Intersect(DateSpan other)
{
    return (this.StartDate >= other.StartDate && this.StartDate <= other.EndDate) ||
           (this.EndDate >= other.StartDate && this.EndDate <= other.EndDate);
}

然后,使用此方法发现可用的时隙:

private List<DateSpan> GetNonOverlappingTimes()
{
    var AvailableHours = new System.Collections.Generic.List<DateSpan>();
    AvailableHours.Add(new DateSpan(new DateTime(2018, 9, 1, 5, 0, 0), 2));
    AvailableHours.Add(new DateSpan(new DateTime(2018, 9, 2, 4, 0, 0), 2));
    AvailableHours.Add(new DateSpan(new DateTime(2018, 9, 2, 5, 0, 0), 2));
    AvailableHours.Add(new DateSpan(new DateTime(2018, 9, 2, 1, 30, 0), 2));
    AvailableHours.Add(new DateSpan(new DateTime(2018, 9, 4, 5, 0, 0), 2));

    var BlockTimes = new System.Collections.Generic.List<DateSpan>();
    BlockTimes.Add(new DateSpan(new DateTime(2018, 9, 1, 10, 0, 0), 2));
    BlockTimes.Add(new DateSpan(new DateTime(2018, 9, 2, 5, 0, 0), 2));
    BlockTimes.Add(new DateSpan(new DateTime(2018, 9, 3, 5, 0, 0), 2));
    BlockTimes.Add(new DateSpan(new DateTime(2018, 9, 4, 4, 0, 0), 2));

    return AvailableHours.Where(x => BlockTimes.All(y => !x.Intersect(y))).ToList();
}