简体   繁体   中英

Getting a timespan by using multiple date ranges against a main date range

I have a requirement to find out a 'valid' timespan by comparing a main Start and End DateTimes with multiple 'ignore' pairs of Start and End DateTimes.

There could be any amount of these 'ignore' pairs and they can range from being between, or even completely covering the initial Start and End DateTime pairs.

Example Inputs and expected outputs are below (using simple time representations for now):

Example 1

Main Start: 04:00 
Main End  : 14:00 

Ignore Pair 1: 03:00 - 06:00 
Ignore Pair 2: 05:00 - 09:00 
Ignore Pair 3: 12:00 - 13:00 

Expected Result: Timespan(4 'Valid' Hours)

Example 2

Main Start: 04:00 
Main End  : 14:00 

Ignore Pair 1: 03:00 - 12:00

Expected Result: Timespan(2 'Valid' Hours)

Example 3

Main Start: 04:00 
Main End  : 14:00 

Ignore Pair 1: 03:00 - 20:00

Expected Result: Timespan(0 'Valid' Hours)

Example 4

Main Start: 04:00 
Main End  : 14:00 

Ignore Pair 1: 08:00 - 12:00

Expected Result: Timespan(6 'Valid' Hours)

Apologies if anything doesn't make sense, please let me know if anything needs more elaboration.

This should give you a List of the valid Ranges. It is a first simple scratch without optimization. The code should explain itself with the comments. If you want to get the amount of "valid" time, just add the ranges in the result with Console.WriteLine("{0} valid hours", valid.Sum(r => (r.End - r.Start).TotalHours)); It's coded under the assumption, that the ranges are validated (start < end)!

Class for storing a time range:

class TimeRange
{
    public DateTime Start { get; set; }
    public DateTime End { get; set; }

    public TimeRange ()
    {

    }
    public TimeRange(TimeSpan todayStart, TimeSpan todayEnd)
    {
        Start = DateTime.Today + todayStart;
        End = DateTime.Today + todayEnd;
    }
}

Testcode:

static void Main(string[] args)
{
    var main = new TimeRange(new TimeSpan(4, 0, 0), new TimeSpan(14, 0, 0));
    var except = new List<TimeRange>{
        new TimeRange(new TimeSpan(3, 0, 0), new TimeSpan(6, 0, 0)),
        new TimeRange(new TimeSpan(5, 0, 0), new TimeSpan(9, 0, 0)),
        new TimeRange(new TimeSpan(12, 0, 0), new TimeSpan(13, 0, 0))
    };

    var valid = GetFreeSlots(main, except);
}

Algorithm:

private static List<TimeRange> GetFreeSlots(TimeRange main, List<TimeRange> except)
{
    // 1. ignore Ranges outside
    except = except.Where(e => main.Start < e.End && main.End > e.Start).ToList();

    // 2. shrink the main timerange from overlapping ranges
    while (true)
    {
        var x = except.FirstOrDefault(e => e.Start <= main.Start);
        if (x != null)
        {
            if (x.End >= main.End)
            {
                return new List<TimeRange>();
            }
            main.Start = x.End;
            except.Remove(x);
        }
        else
            break;
    }

    while (true)
    {
        var x = except.FirstOrDefault(e => e.End >= main.End);
        if (x != null)
        {
            main.End = x.Start;
            except.Remove(x);
        }
        else
            break;
    }

    if (!except.Any())
    {
        return new List<TimeRange> { main };
    }

    // 3. add range[start main to start of the 1. exception] to the list of valid ranges and shrink the main time range to start = end of the 1. exception and go through the procedure again                      
    except.OrderBy(e => e.Start);
    var valid = new List<TimeRange>{new TimeRange{Start = main.Start, End = except[0].Start}};
    main.Start = except[0].End;
    except.RemoveAt(0);
    return valid.Union(GetFreeSlots(main, except)).ToList();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM