查找日期范围之间的差距

时间:2021-02-03 07:53:07

标签: c# .net linq datetime

我需要你的帮助。我想弄清楚如何找到 EndDate 和下一个 StartDate 之间的差距。如果存在差距,我需要返回差距所在的值。你能帮我吗?

我有一个包含开始日期和结束日期的列表。 示例:

  1. 开始日期:2/01/2021 结束日期:2/10/2021
  2. 开始日期:2/11/2021 结束日期:2/15/2021
  3. 开始日期:2/20/2021 结束日期:2/25/2021

1 和 2 之间没有间隙。 2 (Enddate) 和 3 (Stardate) 之间是一个 Gap,需要返回这样的结果:Gap found between 2/16/2021 and 2/19/2021.

我已经尝试过这个,但对我来说效果不佳,你们中有人可以帮助我吗?

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;
        }
    }
}

4 个答案:

答案 0 :(得分:2)

示例

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;
}

输出

16/02/2021 - 19/02/2021

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

答案 1 :(得分:1)

使用链表怎么样?

代码:

using System;
using System.Collections.Generic;

namespace ConsoleApp1
{
    internal static class Program
    {
        private static void Main(string[] args)
        {
            var ranges = new List<DateRange>();

            ranges.Add(
                new DateRange
                {
                    StartDate = new DateTime(2021, 01, 01),
                    EndDate = new DateTime(2021, 01, 31)
                }
            );

            ranges.Add(
                new DateRange
                {
                    StartDate = new DateTime(2021, 02, 10),
                    EndDate = new DateTime(2021, 02, 25)
                }
            );

            var list = new LinkedList<DateRange>(ranges);

            var gaps = new List<LinkedListNode<DateRange>>();

            var current = list.First;

            while (current != null)
            {
                var next = current.Next;

                if (next != null && next.Value.StartDate > current.Value.EndDate)
                    gaps.Add(current);

                current = next;
            }

            Console.WriteLine("Gaps found:");

            foreach (var gap in gaps)
            {
                Console.WriteLine("---------------------------");
                Console.WriteLine("Date Range 1:");
                Console.WriteLine(gap.Value);
                Console.WriteLine("Date Range 2:");
                Console.WriteLine(gap.Next!.Value);
                Console.WriteLine(
                    $"Gap length in minutes: {(gap.Next.Value.StartDate - gap.Value.EndDate).TotalMinutes}");
                Console.WriteLine("---------------------------");
            }
        }
    }

    public class DateRange
    {
        public DateTime StartDate { get; set; }

        public DateTime EndDate { get; set; }

        public override string ToString()
        {
            return $"{nameof(StartDate)}: {StartDate}, {nameof(EndDate)}: {EndDate}";
        }
    }
}

结果:

Gaps found:
---------------------------
Date Range 1:
StartDate: 1/1/2021 12:00:00 AM, EndDate: 1/31/2021 12:00:00 AM
Date Range 2:
StartDate: 2/10/2021 12:00:00 AM, EndDate: 2/25/2021 12:00:00 AM
Gap length in minutes: 14400
---------------------------

答案 2 :(得分:1)

好吧,您可以像这样枚举差距:

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}");

答案 3 :(得分:1)

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

    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;
            }
        }
    }

这允许非常紧凑的 linq 查询

DateRanges.PreviousAndNext()
            .Where(p => p.Previous.EndDate.AddDays(1) < p.Next.StartDate)
            .Select(p => (p.Previous.EndDate, p.Next.StartDate));
相关问题