pandas-dev/pandas · error · ValueError

Offset did not decrement date

Error message

Offset {offset} did not decrement date

What it means

Raised during backward date-range generation (the offset.n < 0 branch of the generator). After applying the offset to the current date, pandas asserts the result is strictly earlier than the current date; if `offset._apply(cur)` yields a date >= cur, the offset is not actually moving backward and the loop would never terminate, so pandas aborts. This is an infinite-loop guard, not a range-bounds check.

Solutions

  1. Verify the offset actually steps backward: test `offset._apply(Timestamp(x)) < Timestamp(x)` for representative x in your range before generating.
  2. If you want a backward range, pass a normal positive offset and let pandas build start->end with start < end, then reverse with [::-1].
  3. For custom DateOffset subclasses, ensure `_apply`/`apply` strictly decreases the input when `n < 0` (multiply the delta by sign(n)).
  4. Check that start > end is paired with an offset whose n < 0 (or rely on pandas to negate), and that no anchor snapping returns the same date.

Example fix

# before
rng = date_range('2024-12-31', '2024-01-01', freq=MyNoOpOffset(-1))  # _apply returns same date

# after - step the offset so apply strictly decreases, or reverse a forward range
rng = date_range('2024-01-01', '2024-12-31', freq='MS')[::-1]
Defensive patterns

Strategy: validation

Validate before calling

import pandas as pd
def offset_decrements(offset, ts):
    return offset._apply(ts) < ts

# before building a backward range
start, end = pd.Timestamp('2024-12-31'), pd.Timestamp('2024-01-01')
if start >= end:
    assert offset_decrements(freq, start), f'offset {freq} does not decrement; date_range would fail'

Type guard

def is_backward_offset(offset: pd.offsets.BaseOffset, sample: pd.Timestamp) -> bool:
    return offset._apply(sample) < sample

Try / catch

try:
    rng = pd.date_range(start, end, freq=freq)
except ValueError as e:
    if 'did not decrement date' in str(e):
        rng = pd.date_range(end, start, freq=freq)[::-1]  # build forward, reverse
    else:
        raise

Prevention

When it happens

Trigger: Constructing a date_range/DatetimeIndex that iterates backward (start > end with a negative-direction offset, or an offset whose `.n < 0`) where the offset's `_apply` returns a value that does not decrease the timestamp. Happens with custom DateOffset subclasses whose apply is a no-op, with offsets that roll forward to the same anchored point (e.g. some MonthEnd / YearBegin anchorings on boundary dates), or with semi-monthend offsets that snap instead of step.

Common situations: Custom DateOffset subclasses that forget to move the date in one direction; calling `date_range(start, end, freq=<negative offset>)` where start > end but the offset increments; using `pd.offsets.SemiMonthEnd(-1)` or similar negative offsets on dates where the rule resolves to the same day; version upgrades that changed anchor semantics for BusinessHour/CustomBusinessHour.

Related errors


AI-assisted analysis of pandas-dev/pandas@3b7651241d (2026-08-11). Data as JSON: /api/errors/cf130195fc75d099. Report an issue: GitHub.

Appendix: source

Thrown at pandas/core/arrays/datetimes.py:3288

            next_date = offset._apply(cur)
            next_date = next_date.as_unit(unit)
            if next_date <= cur:
                raise ValueError(f"Offset {offset} did not increment date")
            cur = next_date
    else:
        while cur >= end:
            yield cur

            if cur == end:
                # GH#24252 avoid overflows by not performing the addition
                # in offset.apply unless we have to
                break

            # faster than cur + offset
            next_date = offset._apply(cur)
            next_date = next_date.as_unit(unit)
            if next_date >= cur:
                raise ValueError(f"Offset {offset} did not decrement date")
            cur = next_date

View on GitHub (pinned to 3b7651241d)