.NET Fiddle

CSharp · Console

/Program.cs

using System;
using System.Linq;

using static MoreLinq.Extensions.GroupAdjacentExtension;
using static MoreLinq.Extensions.ScanRightExtension;
using static MoreLinq.Extensions.WindowRightExtension;
using static MoreLinq.Extensions.ForEachExtension;

var items = new[] {
    new {
        Id = 1, 
        Quantity = 1,
        StartDate = DateTime.Parse("2021-03-10"),
        EndDate = DateTime.Parse("2021-03-21")
    },
    new {
        Id = 2,
        Quantity = 1,
        StartDate = DateTime.Parse("2021-03-10"),
        EndDate = DateTime.Parse("2021-03-21")
    },
    new {
        Id = 3, 
        Quantity = 2,
        StartDate = DateTime.Parse("2021-03-10"), 
        EndDate = DateTime.Parse("2021-03-23")
    },
    new {
        Id = 4, 
        Quantity = 1,
        StartDate = DateTime.Parse("2021-03-10"), 
        EndDate = DateTime.Parse("2021-03-25")
    }
};

items
	// aggregate identical end dates
	.GroupAdjacent(x => x.EndDate)
    .Select(xs => xs.Aggregate(
        new {
            Ids = Enumerable.Empty<int>(),
            Quantity = 0,
            StartDate = default(DateTime),
            EndDate = default(DateTime)
        },
        (acc, curr) => new {
            Ids = acc.Ids.Append(curr.Id),
            Quantity = acc.Quantity + curr.Quantity,
            curr.StartDate,
            curr.EndDate
        }))
    
    // cut-off overlapping start dates
    .WindowRight(2)
    .Select(win => win.Count == 1
        ? win[0]
        : new {
            win[1].Ids,
            win[1].Quantity,
            StartDate = win[0].EndDate.AddDays(1),
            win[1].EndDate
        })
    
    // accumulate IDs and quantities
    .ScanRight((curr, prev) => new {
        Ids = curr.Ids.Concat(prev.Ids),
        Quantity = curr.Quantity + prev.Quantity,
        curr.StartDate,
        curr.EndDate
    })
	
	// print
	.Select(x => $"{{ Ids: [{string.Join(',', x.Ids)}], Quantity: {x.Quantity}, StartDate: {x.StartDate.ToShortDateString()}, EndDate: {x.EndDate.ToShortDateString()} }}")
	.ForEach(x => Console.WriteLine(x));
;