C# 找出日期范围之间的差距

C# 找出日期范围之间的差距,c#,.net,linq,datetime,C#,.net,Linq,Datetime,我需要你的帮助。我正试图找出如何找到EndDate和下一个StartDate之间的差距。如果存在间隙,我需要返回间隙所在的值。你能帮帮我吗 我有一张有开始日期和结束日期的清单。 例如: 开始日期:2021年1月2日结束日期:2021年10月2日 开始日期:2021年11月2日结束日期:2021年15月2日 开始日期:2021年2月20日结束日期:2021年2月25日 1和2之间没有间隙。介于2(Enddate)和3(Stardate)之间是一个差距,需要返回如下结果:在2021年2月16日和20

我需要你的帮助。我正试图找出如何找到EndDate和下一个StartDate之间的差距。如果存在间隙,我需要返回间隙所在的值。你能帮帮我吗

我有一张有开始日期和结束日期的清单。 例如:

  • 开始日期:2021年1月2日结束日期:2021年10月2日
  • 开始日期:2021年11月2日结束日期:2021年15月2日
  • 开始日期:2021年2月20日结束日期:2021年2月25日
  • 1和2之间没有间隙。介于2(Enddate)和3(Stardate)之间是一个差距,需要返回如下结果:在2021年2月16日和2021年2月19日之间找到差距。

    我已经试过这个了,但对我不起作用。嗯,你们中有人能帮我吗

    static void Main(string[] args)
        {
            List<DateRanges> DateRanges = new List<DateRanges>();
            DateRanges.Add(new DateRanges() { StartDate = new DateTime(2021, 01, 01), EndDate = new DateTime(2021, 01, 31) });
            DateRanges.Add(new DateRanges() { StartDate = new DateTime(2021, 02, 10), EndDate = new DateTime(2021, 02, 25) });
    
            var missing = DateRangeEnumerable.GetDates(DateRanges);
            var ranges = missing.GetRanges();
        }
    
    
    public class DateRanges
    {
        public DateTime StartDate { get; set; }
        public DateTime EndDate { get; set; }
        //public DateRanges(DateTime Start, DateTime End)
        //{
        //    StartDate = Start;
        //    EndDate = End;
        //}
    }
    
    
    public static class DateRangeEnumerable
    {
        public static IEnumerable<DateTime> GetDates(this IEnumerable<DateRanges> source)
        {
            var sortedSource = source.OrderBy(r => r.StartDate);
    
            foreach (var range in sortedSource)
            {
                var d = range.StartDate;
                while (d < range.EndDate)
                {
                    yield return d;
                    d = d.AddDays(1);
                }
            }
        }
        public static IEnumerable<DateRanges> GetRanges(this IEnumerable<DateTime> source)
        {
            var sortedSource = source.OrderBy(d => d);
            var enumerator = sortedSource.GetEnumerator();
    
            if (!enumerator.MoveNext())
                yield break;
    
            DateTime from = enumerator.Current;
            DateTime prev = from;
    
            while (true)
            {
                while (true)
                {
                    if (enumerator.MoveNext())
                    {
                        if (enumerator.Current == prev.AddDays(1))
                            prev = enumerator.Current;
                        else
                            break;
                    }
                    else
                    {
                        yield return new DateRanges() { StartDate = from, EndDate = prev.AddDays(1) };
                        yield break;
                    }
    
                }
    
                yield return new DateRanges() { StartDate = from, EndDate = prev.AddDays(1) };
    
                from = enumerator.Current;
                prev = enumerator.Current;
            }
        }
    }
    
    static void Main(字符串[]args)
    {
    列表日期范围=新列表();
    Add(new DateRanges(){StartDate=new DateTime(2021,01,01),EndDate=new DateTime(2021,01,31)});
    Add(new DateRanges(){StartDate=new DateTime(2021,02,10),EndDate=new DateTime(2021,02,25)});
    var missing=DateRangeEnumerable.GetDates(DateRanges);
    var ranges=缺少.GetRanges();
    }
    公共类日期范围
    {
    公共日期时间起始日期{get;set;}
    公共日期时间结束日期{get;set;}
    //公共日期范围(日期时间开始、日期时间结束)
    //{
    //开始日期=开始;
    //结束日期=结束;
    //}
    }
    公共静态类DateRangeEnumerable
    {
    公共静态IEnumerable GetDates(此IEnumerable源)
    {
    var sortedSource=source.OrderBy(r=>r.StartDate);
    foreach(分拣源中的var范围)
    {
    var d=范围.StartDate;
    而(dd);
    var枚举器=sortedSource.GetEnumerator();
    如果(!enumerator.MoveNext())
    屈服断裂;
    DateTime from=枚举数。当前;
    DateTime prev=起始日期;
    while(true)
    {
    while(true)
    {
    if(枚举数.MoveNext())
    {
    if(enumerator.Current==prev.AddDays(1))
    prev=枚举数。当前值;
    其他的
    打破
    }
    其他的
    {
    返回新的DateRanges(){StartDate=from,EndDate=prev.AddDays(1)};
    屈服断裂;
    }
    }
    返回新的DateRanges(){StartDate=from,EndDate=prev.AddDays(1)};
    from=枚举数。当前;
    prev=枚举数。当前值;
    }
    }
    }
    
    使用链表怎么样?

    代码:


    Exmaple

    var dateRanges = new List<DateRanges>
    {
       new() {StartDate = new DateTime(2021, 2, 01), EndDate = new DateTime(2021, 2, 10)},
       new() {StartDate = new DateTime(2021, 02, 11), EndDate = new DateTime(2021, 02, 15)},
       new() {StartDate = new DateTime(2021, 02, 20), EndDate = new DateTime(2021, 02, 25)}
    };
    
    var end = dateRanges.First().EndDate;
    foreach (var range in dateRanges.Skip(1))
    {
       if(end.AddDays(1) <  range.StartDate )
          Console.WriteLine($"{end.AddDays(1):d} - {range.StartDate.AddDays(-1):d}");
       end = range.EndDate;
    }
    

    免责声明:它不包含错误检查、排序、代码中没有暗示的内容,并且假设日期没有时间值。它只是复制了您的描述

    那么,您可以像这样列举差距:

    private static IEnumerable<DateRanges> Gaps(IEnumerable<DateRanges> dates) {
      var source = dates
        .OrderBy(range => range.StartDate); 
    
      DateTime last = DateTime.MinValue;
      bool first = true;
    
      foreach (var range in source) {
        if (!first && range.StartDate.AddDays(1) > last)
          yield return new DateRanges() {
            StartDate = last.AddDays(1), 
            EndDate = range.StartDate.AddDays(-1)) 
         }; 
    
        // In case of overlapping periods we have to pick the latest date         
        last = first || range.EndDate > last
          ? range.EndDate 
          : last;
    
        first = false; 
      }
    }
    

    我喜欢使用返回后续项对的通用扩展方法:

        public static IEnumerable<(T Previous, T Next)> PreviousAndNext<T>(this IEnumerable<T> self)
        {
            using (var iter = self.GetEnumerator())
            {
                if (!iter.MoveNext())
                    yield break;
                var previous = iter.Current;
                while (iter.MoveNext())
                {
                    var next = iter.Current;
                    yield return (previous, next);
                    previous = next;
                }
            }
        }
    
    公共静态IEnumerable Previous和Next(此IEnumerable self)
    {
    使用(var iter=self.GetEnumerator())
    {
    如果(!iter.MoveNext())
    屈服断裂;
    var-previous=iter.电流;
    while(iter.MoveNext())
    {
    var next=iter.电流;
    收益率回报率(上一个、下一个);
    上一个=下一个;
    }
    }
    }
    
    这允许非常紧凑的linq查询

    DateRanges.PreviousAndNext()
                .Where(p => p.Previous.EndDate.AddDays(1) < p.Next.StartDate)
                .Select(p => (p.Previous.EndDate, p.Next.StartDate));
    
    DateRanges.PreviousAndNext()
    .Where(p=>p.Previous.EndDate.AddDays(1)(p.Previous.EndDate,p.Next.StartDate));
    
    为什么要将其转换为日期?我将遍历这些范围,记住上一个结束日期,并将其与当前开始日期进行比较。如果其不相等,则创建一个新的“缺失范围”,从上一个结束日期+1开始,到当前开始日期-1结束。如果要对范围进行排序,请使用自定义比较器,使用
    OrderBy
    列表进行排序。排序
    ,不要扩展范围。这样做会丢失范围信息嗨,谢谢。但是这行“收益率回报(last.AddDays(1),range.StartDate.AddDays(-1));”不起作用。因为它试图返回日期时间而不是日期范围。@Ronak:谢谢!我已经编辑了添加的应答构造函数调用。
    private static IEnumerable<DateRanges> Gaps(IEnumerable<DateRanges> dates) {
      var source = dates
        .OrderBy(range => range.StartDate); 
    
      DateTime last = DateTime.MinValue;
      bool first = true;
    
      foreach (var range in source) {
        if (!first && range.StartDate.AddDays(1) > last)
          yield return new DateRanges() {
            StartDate = last.AddDays(1), 
            EndDate = range.StartDate.AddDays(-1)) 
         }; 
    
        // In case of overlapping periods we have to pick the latest date         
        last = first || range.EndDate > last
          ? range.EndDate 
          : last;
    
        first = false; 
      }
    }
    
    foreach (var gap in Gaps(dateRanges))
      Console.WriteLine($"Gap found between {gap.StartDate} and {gap.EndDate}");
    
        public static IEnumerable<(T Previous, T Next)> PreviousAndNext<T>(this IEnumerable<T> self)
        {
            using (var iter = self.GetEnumerator())
            {
                if (!iter.MoveNext())
                    yield break;
                var previous = iter.Current;
                while (iter.MoveNext())
                {
                    var next = iter.Current;
                    yield return (previous, next);
                    previous = next;
                }
            }
        }
    
    DateRanges.PreviousAndNext()
                .Where(p => p.Previous.EndDate.AddDays(1) < p.Next.StartDate)
                .Select(p => (p.Previous.EndDate, p.Next.StartDate));