heatmapGrid function

List<List<int>> heatmapGrid(
  1. Map<DateTime, int> daily,
  2. DateTime start,
  3. DateTime end, {
  4. int weekStartsOn = DateTime.monday,
})

A list of weeks (each a length-7 list of counts) covering start..end inclusive, with each inner row beginning on weekStartsOn.

Missing days read 0. The first row is back-padded to the most recent weekStartsOn on/before start, and the last row is forward-padded to the end of its week, so the grid is rectangular (every row length 7). daily is the date-keyed map from dailyCounts; its keys are matched date-only.

Example:

final Map<DateTime, int> d = dailyCounts(<DateTime>[DateTime(2026, 3, 3)]);
heatmapGrid(d, DateTime(2026, 3, 2), DateTime(2026, 3, 8));
// single week starting Monday 2026-03-02, with a 1 on Tuesday.

Audited: 2026-06-12 11:26 EDT

Implementation

List<List<int>> heatmapGrid(
  Map<DateTime, int> daily,
  DateTime start,
  DateTime end, {
  int weekStartsOn = DateTime.monday,
}) {
  final DateTime gridStart = _weekStart(_dateOnly(start), weekStartsOn);
  final DateTime lastDay = _dateOnly(end);

  final List<List<int>> weeks = <List<int>>[];
  List<int> week = <int>[];
  DateTime day = gridStart;

  // Walk whole weeks of 7 days until we have passed [end]; the last week is
  // completed even when [end] lands mid-week, keeping every row length 7.
  while (!day.isAfter(lastDay) || week.isNotEmpty) {
    week.add(day.isBefore(_dateOnly(start)) ? 0 : (daily[day] ?? 0));
    // Step with calendar fields, NOT `day.add(Duration(days: 1))`: a fixed 24h
    // step on a LOCAL midnight lands at 01:00 across a spring-forward DST day,
    // which then misses the date-only midnight keys in `daily` and reads 0.
    day = DateTime(day.year, day.month, day.day + 1);
    if (week.length == DateTime.daysPerWeek) {
      weeks.add(week);
      week = <int>[];
    }
  }
  return weeks;
}