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 */
514200cookie-checkFlatten time periods