Flatten time periods

Date: 2021-06-24
public class TimeRange {
    public DateTime? Start { get; set; }
    public DateTime? End { get; set; }

    public static IEnumerable<T> Select<T> (params T[] args) => args;

        // [---------------]     [----------] <= children
        //            [---------------]       <= children  
        // ==>
        //     [-------------------------]    <= parent
        //     [-----][----][---][-------]
        public static IEnumerable<TimeRange> GetPeriodsFlattened(ITimeRange parent, IEnumerable<ITimeRange> children)
        {
            if (!children.Any())
            {
                yield return new TimeRange(parent.Start, parent.End);
                yield break;
            }

            var allTimesInParent = children.SelectMany(x => LinqHelper.Select(x.Start, x.End))
                .Concat(LinqHelper.Select(parent.Start, parent.End))
                .Where(x => x.HasValue && x >= parent.Start && x <= parent.End)
                .OrderBy(x => x).Distinct().ToList();

            if (allTimesInParent.Count < 2)
            {
                yield return new TimeRange(parent.Start, parent.End);
                yield break;
            }

            DateTime? prev = null;
            foreach (var curr in allTimesInParent)
            {
                if (prev != null)
                    yield return new TimeRange(prev, curr);
                prev = curr;
            }
        }
}

void Main () {
    var ranges = new List<TimeRange> () {
        new TimeRange {
            Start = null,
            End = new DateTime (2020, 1, 15)
        },
        new TimeRange {
            Start = new DateTime (2020, 1, 14),
            End = new DateTime (2020, 1, 18)
        },
        new TimeRange {
            Start = new DateTime (2020, 1, 20),
            End = null
        }
    };

    var parentRange = new TimeRange () {
        Start = new DateTime (2020, 1, 12),
        End = new DateTime (2020, 2, 28)
    };

    var flattened = TimeRange.GetPeriodsFlattened (parentRange, ranges);
    foreach (var range in flattened) {
        Console.WriteLine (range.Start.ToString () + " - " + range.End.ToString ());
    }
}
/* CONSOLE OUTPUT:
12-1-2020 00:00:00 - 14-1-2020 00:00:00
14-1-2020 00:00:00 - 15-1-2020 00:00:00
15-1-2020 00:00:00 - 18-1-2020 00:00:00
18-1-2020 00:00:00 - 20-1-2020 00:00:00
20-1-2020 00:00:00 - 28-2-2020 00:00:00
*/
51420cookie-checkFlatten time periods