currentCycle function

({DateTime end, DateTime start}) currentCycle(
  1. DateTime on,
  2. int anchorDay
)

The half-open [start, end) billing cycle that contains on for anchorDay.

start is the billing date on/before on's date; end is the next billing date (the start of the following cycle), so the range is half-open and two adjacent cycles never both claim the boundary day. anchorDay must be 1..31.

Example:

// Anchor 15, the 20th falls in the cycle that opened on the 15th.
currentCycle(DateTime(2026, 3, 20), 15);
// (start: 2026-03-15, end: 2026-04-15)

Audited: 2026-06-12 11:26 EDT

Implementation

({DateTime start, DateTime end}) currentCycle(DateTime on, int anchorDay) {
  _checkAnchor(anchorDay);

  final DateTime onDate = _dateOnly(on);
  final DateTime thisMonth = billingDateInMonth(onDate.year, onDate.month, anchorDay);

  // The cycle start is this month's billing date if [on] is on/after it,
  // otherwise the previous month's billing date.
  final DateTime start = thisMonth.isAfter(onDate)
      ? billingDateInMonth(onDate.year, onDate.month - 1, anchorDay)
      : thisMonth;
  final DateTime end = billingDateInMonth(start.year, start.month + 1, anchorDay);
  return (start: start, end: end);
}