查找日期范围.NET中的每小时差距

时间:2018-01-22 15:53:36

标签: c# .net linq

我有一个可用的课程

public class AvailabilityDto 
{
    public DateTime StartDateTime { get; set; }

    public DateTime EndDateTime { get; set; }
}

我正在尝试创建一个报告,找出可用性中的差距。 给出可用性类的列表,以及在其间搜索的开始和结束日期。我试图在可用性中找到差距

这是为了看看是否有人在通常的办公时间9-5之外随叫随到。

这是我目前的实施,效率非常低,无效:

    foreach(var entry in rota) {

     //get all items from the list that are available out of office hours
    //and order them by start time

     var outOfHoursAvailibilities = entry.Availabilities
      .Where(m => m.EndDateTime.Hour <= 9 || m.StartDateTime.Hour >= 17)
      .OrderBy(m => m.StartDateTime)
      .ToList();

     var i = 0;

     while (i < outOfHoursAvailibilities.Count) {

      var currentStart = outOfHoursAvailibilities[i];
      var next = outOfHoursAvailibilities[i + 1];

      //if first ends before second starts,
      if (currentStart.EndDateTime < next.StartDateTime)  
      {
       //this means we have a gap -- until the next next one
       currentStart = next;
       i++;
       next = outOfHoursAvailibilities[i + 1];

       var missingAvailabilty = new AvailabilityDto {
        StartDateTime = currentStart.EndDateTime,
         EndDateTime = next.StartDateTime,    
       };

       gaps.Add(missingAvailabilty);

      }

      i++;
     }
    } 

2 个答案:

答案 0 :(得分:0)

设置currentStart = next时,会覆盖具有缺失可用性StartDateTime的对象。当您实例化新AvailabilityDto时,您将值设置为下一个可用性,而不是您找到的当前差距。我认为您不需要设置下一个当前的电流。

尝试此操作(未将next设置为currentStart):

if (currentStart.EndDateTime < next.StartDateTime)  
{
    var missingAvailabilty = new AvailabilityDto {
        StartDateTime = currentStart.EndDateTime,
        EndDateTime = next.StartDateTime,    
    };

    gaps.Add(missingAvailabilty);
}

答案 1 :(得分:0)

我认为,如果您按StartDateTime然后EndDateTime订购可用性,只需跟踪最新结束时间,就可以轻松实现您想要的效果。如果您遇到的开始时间晚于当前最后结束时间,则表示您已找到差距。在这里,我将其作为扩展方法实现:

public static class EnumerableExtensions
{
    public static IEnumerable<AvailabilityDto> FindAvailabilityGaps(this IEnumerable<AvailabilityDto> source)
    {
        if (source == null)
        {
            yield break;
        }

        var sorted = source.OrderBy(x => x.StartDateTime).ThenBy(x => x.EndDateTime);

        using (var e = sorted.GetEnumerator())
        {
            if (!e.MoveNext())
            {
                yield break;
            }

            var latestEndTime = e.Current.EndDateTime;

            while (e.MoveNext())
            {
                if (e.Current.StartDateTime > latestEndTime)
                {
                    yield return new AvailabilityDto
                    {
                        StartDateTime = latestEndTime,
                        EndDateTime = e.Current.StartDateTime
                    };
                }

                if (e.Current.EndDateTime > latestEndTime)
                {
                    latestEndTime = e.Current.EndDateTime;
                }
            }
        }
    }
}

你会这样称呼:

var outOfHoursAvailibilities = 
    entry
    .Availabilities
    .Where(m => m.EndDateTime.Hour <= 9 || m.StartDateTime.Hour >= 17)
    .FindAvailabilityGaps();

我不清楚您是否在示例中使用Entity Framework或其他ORM。如果是这样,您将需要在调用扩展方法之前调用AsEnumerable,因为LINQ提供程序将无法将FindAvailabilityGaps转换为SQL。像这样:

var outOfHoursAvailibilities = 
    entry
    .Availabilities
    .Where(m => m.EndDateTime.Hour <= 9 || m.StartDateTime.Hour >= 17)
    .AsEnumerable()
    .FindAvailabilityGaps();

当然,如果您不想使用扩展方法,您可以采用上述方法的内容并以您喜欢的方式使用它。

顺便说一句,我不认为你排除办公时间的谓词会达到你想要的效果。我认为@ 5ar的评论是正确的:

m => !(m.StartDateTime.Hour >= 9 || m.EndDateTime.Hour <= 17)