findGaps function

List<({DateTime end, DateTime start})> findGaps(
  1. List<DateTime> timestamps,
  2. Duration expectedInterval, {
  3. double tolerance = 0.5,
})

Gaps [start, end] (the inclusive bounding sample pair) where consecutive timestamps are spaced more than expectedInterval * (1 + tolerance) apart.

timestamps is copied and sorted, so order in does not matter. tolerance is a non-negative fraction of slack on top of the expected interval. With fewer than two samples there are no pairs, so the result is empty.

Example:

findGaps(
  <DateTime>[DateTime(2026, 1, 1, 0), DateTime(2026, 1, 1, 3)],
  const Duration(hours: 1),
); // one gap from 00:00 to 03:00 (3h delta > 1.5h threshold)

Audited: 2026-06-12 11:26 EDT

Implementation

List<({DateTime start, DateTime end})> findGaps(
  List<DateTime> timestamps,
  Duration expectedInterval, {
  double tolerance = 0.5,
}) {
  // Copy before sorting so the caller's list is never mutated as a side effect.
  final List<DateTime> sorted = List<DateTime>.of(timestamps)
    ..sort((DateTime a, DateTime b) => a.compareTo(b));

  // A delta beyond this many microseconds between neighbors is a gap; computing
  // it once in microseconds avoids per-pair Duration allocation.
  final int thresholdMicros = (expectedInterval.inMicroseconds * (1 + tolerance)).round();

  final List<({DateTime start, DateTime end})> gaps = <({DateTime start, DateTime end})>[];
  for (int i = 1; i < sorted.length; i++) {
    final DateTime prev = sorted[i - 1];
    final DateTime curr = sorted[i];
    if (curr.difference(prev).inMicroseconds > thresholdMicros) {
      gaps.add((start: prev, end: curr));
    }
  }
  return gaps;
}