C#
date ranges
list manipulation
programming tutorial
code optimization

How to consolidate date ranges in a list in C

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Consolidating date ranges means merging overlapping or contiguous intervals into the smallest set of non-overlapping ranges. This pattern appears in booking systems, reporting windows, entitlement calculations, and maintenance schedules. A naïve pairwise merge can be expensive and fragile. The standard solution is to sort by start date, then scan once while extending the current interval when overlap exists.

A correct implementation must define interval semantics clearly: should adjacent ranges be merged (end + 1 day == next start), and are endpoints inclusive? Once those rules are explicit, the algorithm is simple and efficient.

Core Sections

1. Define a range model

csharp
1public record DateRange(DateOnly Start, DateOnly End)
2{
3    public DateRange
4    {
5        if (End < Start) throw new ArgumentException("End must be >= Start");
6    }
7}

Using DateOnly avoids time-of-day ambiguity when full timestamps are not needed.

2. Sort then merge in one pass

csharp
1public static List<DateRange> Consolidate(IEnumerable<DateRange> input)
2{
3    var sorted = input.OrderBy(r => r.Start).ThenBy(r => r.End).ToList();
4    if (sorted.Count == 0) return new List<DateRange>();
5
6    var merged = new List<DateRange>();
7    var current = sorted[0];
8
9    for (int i = 1; i < sorted.Count; i++)
10    {
11        var next = sorted[i];
12
13        // merge overlapping or contiguous ranges
14        if (next.Start <= current.End.AddDays(1))
15        {
16            current = current with { End = next.End > current.End ? next.End : current.End };
17        }
18        else
19        {
20            merged.Add(current);
21            current = next;
22        }
23    }
24
25    merged.Add(current);
26    return merged;
27}

Time complexity is O(n log n) due to sorting, with linear merge after that.

3. Example usage

csharp
1var ranges = new List<DateRange>
2{
3    new(new DateOnly(2024, 1, 1), new DateOnly(2024, 1, 5)),
4    new(new DateOnly(2024, 1, 3), new DateOnly(2024, 1, 10)),
5    new(new DateOnly(2024, 1, 20), new DateOnly(2024, 1, 25)),
6    new(new DateOnly(2024, 1, 26), new DateOnly(2024, 1, 30))
7};
8
9var merged = Consolidate(ranges);

Result becomes two consolidated ranges: 01-01..01-10 and 01-20..01-30.

4. Handle DateTime ranges carefully

If you use DateTime, decide timezone and inclusivity explicitly.

csharp
public record TimeRange(DateTime StartUtc, DateTime EndUtc);

For cross-system data, normalize to UTC before merge to avoid daylight-saving surprises.

5. Make merge policy configurable

Some domains merge only overlapping ranges, not contiguous ones.

csharp
1bool ShouldMerge(DateRange current, DateRange next, bool mergeContiguous)
2{
3    return mergeContiguous
4        ? next.Start <= current.End.AddDays(1)
5        : next.Start <= current.End;
6}

A policy flag avoids forking nearly identical implementations.

6. Add focused tests

csharp
1[Fact]
2public void Consolidate_MergesOverlappingAndAdjacent()
3{
4    var input = new[] {
5        new DateRange(new DateOnly(2024,1,1), new DateOnly(2024,1,2)),
6        new DateRange(new DateOnly(2024,1,3), new DateOnly(2024,1,4))
7    };
8
9    var merged = Consolidate(input);
10    Assert.Single(merged);
11}

Tests should include empty input, single item, nested ranges, and adjacency boundaries.

Common Pitfalls

  • Failing to sort before merge, which breaks correctness for unsorted input.
  • Ignoring inclusive/exclusive endpoint semantics and merging incorrectly at boundaries.
  • Mixing time zones in DateTime ranges without normalization.
  • Forgetting to validate End >= Start, allowing invalid intervals into merge logic.
  • Rewriting pairwise merge loops that degrade to quadratic complexity.

Summary

To consolidate date ranges in C#, sort by start date and merge in a single pass based on explicit overlap/adjacency rules. Use strong range models, normalize timezones when necessary, and test boundary cases thoroughly. This approach is efficient, maintainable, and reliable for both scheduling and reporting workloads.

A practical way to harden this topic in real projects is to add a small operational checklist and treat it as part of your engineering standard, not a one-off fix. Start by creating one minimal failing case and one passing case that represent real input from production logs. Then automate those checks in CI so regressions are caught before release. Add lightweight instrumentation around the critical branch where this logic runs, and include structured fields that let you filter by version, environment, and error type. This gives you fast feedback when behavior changes after dependency upgrades or refactors.

For long-term maintainability on how to consolidate date ranges in a list in c, keep one source of truth for helper logic instead of duplicating variants across services or UI layers. Document assumptions near the code, including data format, edge-case behavior, and expected fallback policy. During code review, verify that example inputs and tests cover empty values, malformed values, and high-volume scenarios. Teams that combine explicit assumptions, repeatable tests, and basic observability typically avoid the same category of bug recurring every quarter.


Course illustration
Course illustration

All Rights Reserved.