splitAt method

List<Period> splitAt(
  1. Set<DateTime> dates, {
  2. Duration periodBetween = Duration.zero,
})

Splits the period in multiple periods at the given dates. The periodBetween is the duration between each period. The dates not included in the period are ignored. The dates will be sorted before splitting.

The periodBetween must be greater than or equals to zero and less than the duration of the period. The sum of the period between dates must be less than the duration of the period.

If the periodBetween is zero, the periods will be contiguous. If the periodBetween is greater than zero, the periods will be separated by the given duration.

If the dates are empty, the period is returned. If the dates are not empty, the period is split at the given dates.

Example:

final period = Period(
  start: DateTime(2020, 1, 1),
  end: DateTime(2020, 1, 31),
);

final periods = period.splitAt(
  {
    DateTime(2020, 1, 10),
    DateTime(2020, 1, 20),
  },
  periodBetween: const Duration(days: 1),
);

// periods = [
//   Period(
//     start: DateTime(2020, 1, 1),
//     end: DateTime(2020, 1, 10),
//   ),
//   Period(
//     start: DateTime(2020, 1, 11),
//     end: DateTime(2020, 1, 20),
//   ),
//   Period(
//     start: DateTime(2020, 1, 21),
//     end: DateTime(2020, 1, 31),
//   ),
// ]

Implementation

List<Period> splitAt(
  Set<DateTime> dates, {
  Duration periodBetween = Duration.zero,
}) {
  if ((periodBetween < Duration.zero) || (duration <= periodBetween)) {
    throw ArgumentError.value(
      periodBetween,
      'periodBetween',
      'The period between dates must be greater than or equals to zero and '
          'less than the duration of the period.',
    );
  }
  final periods = <Period>[];
  final sortedValidDates = [...dates.where(contains)]..sort();
  final resultDuration = periodBetween * sortedValidDates.length;
  if (resultDuration > duration) {
    throw ArgumentError.value(
      dates,
      'dates',
      'The sum of the period between dates is greater than the duration of '
          'the period.',
    );
  }
  for (final date in sortedValidDates.sublist(sortedValidDates.length - 1)) {
    if (periods.isEmpty) {
      periods.add(Period(start: start, end: date));
    } else {
      final last = periods.last;
      if (last.end.add(periodBetween).isBefore(date)) {
        periods.add(Period(start: last.end.add(periodBetween), end: date));
      } else {
        final start = last.end.add(periodBetween);
        periods.add(Period(start: start, end: start));
      }
    }
  }
  if (periods.isNotEmpty) {
    final last = periods.last;
    if (last.end.add(periodBetween).isBefore(end)) {
      periods.add(Period(start: last.end.add(periodBetween), end: end));
    } else {
      final start = last.end.add(periodBetween);
      periods.add(Period(start: start, end: start));
    }
  } else {
    periods.add(this);
  }
  return periods;
}