def _generate_linear_date_range_with_freq(start, end, periods, freq):
    """Generate a regular range of cftime.datetime objects with a
    given frequency.

    Adapted from pandas.tseries.offsets.generate_range (now at
    pandas.core.arrays.datetimes._generate_range).

    Parameters
    ----------
    start : cftime.datetime, or None
        Start of range
    end : cftime.datetime, or None
        End of range
    periods : int, or None
        Number of elements in the sequence
    freq: str
        Step size between cftime.datetime objects. Not None.

    Returns
    -------
    A generator object of cftime.datetime objects
    """
    offset = to_offset(freq)

    if start:
        # From pandas GH 56147 / 56832 to account for negative direction and
        # range bounds
        if offset.n >= 0:
            start = offset.rollforward(start)
        else:
            start = offset.rollback(start)

    if periods is None and end < start and offset.n >= 0:
        end = None
        periods = 0

    if end is None:
        end = start + (periods - 1) * offset

    if start is None:
        start = end - (periods - 1) * offset

    current = start
    if offset.n >= 0:
        while current <= end:
            yield current

            next_date = current + offset
            if next_date <= current:
                raise ValueError(f"Offset {offset} did not increment date")
            current = next_date
    else:
        while current >= end:
            yield current

            next_date = current + offset
            if next_date >= current:
                raise ValueError(f"Offset {offset} did not decrement date")
            current = next_date
Generate a regular range of cftime.datetime objects with a
    given frequency.

    Adapted from pandas.tseries.offsets.generate_range (now at
    pandas.core.arrays.datetimes._generate_range).

    Parameters
    ----------
    start : cftime.datetime, or None
        Start of range
    end : cftime.datetime, or None
        End of range
    periods : int, or None
        Number of elements in the sequence
    freq: str
        Step size between cftime.datetime objects. Not None.

    Returns
    -------
    A generator object of cftime.datetime objects
    
xarray/coding/cftime_offsets.py