def _cftime_range(
    start=None,
    end=None,
    periods=None,
    freq=None,
    normalize=False,
    name=None,
    inclusive: InclusiveOptions = "both",
    calendar="standard",
) -> CFTimeIndex:
    """Return a fixed frequency CFTimeIndex.

    Parameters
    ----------
    start : str or cftime.datetime, optional
        Left bound for generating dates.
    end : str or cftime.datetime, optional
        Right bound for generating dates.
    periods : int, optional
        Number of periods to generate.
    freq : str or None, default: "D"
        Frequency strings can have multiples, e.g. "5h" and negative values, e.g. "-1D".
    normalize : bool, default: False
        Normalize start/end dates to midnight before generating date range.
    name : str, default: None
        Name of the resulting index
    inclusive : {"both", "neither", "left", "right"}, default "both"
        Include boundaries; whether to set each bound as closed or open.
    calendar : str, default: "standard"
        Calendar type for the datetimes.

    Returns
    -------
    CFTimeIndex

    Notes
    -----
    see cftime_range
    """
    if freq is None and any(arg is None for arg in [periods, start, end]):
        freq = "D"

    # Adapted from pandas.core.indexes.datetimes._generate_range.
    if count_not_none(start, end, periods, freq) != 3:
        raise ValueError(
            "Exactly three of 'start', 'end', 'periods', or 'freq' must be "
            "specified to generate a date range. Note that 'freq' defaults to "
            "'D' in the event that any of 'start', 'end', or 'periods' are "
            "None."
        )

    start = _get_normalized_cfdate(start, calendar, normalize)
    end = _get_normalized_cfdate(end, calendar, normalize)

    if freq is None:
        dates = _generate_linear_date_range(start, end, periods)
    else:
        dates = np.array(
            list(_generate_linear_date_range_with_freq(start, end, periods, freq))
        )

    if not TYPE_CHECKING and inclusive not in get_args(InclusiveOptions):
        raise ValueError(
            f"Argument `inclusive` must be either 'both', 'neither', "
            f"'left', or 'right'.  Got {inclusive}."
        )

    if len(dates) and inclusive != "both":
        if inclusive != "left" and dates[0] == start:
            dates = dates[1:]
        if inclusive != "right" and dates[-1] == end:
            dates = dates[:-1]

    return CFTimeIndex(dates, name=name)
Return a fixed frequency CFTimeIndex.

    Parameters
    ----------
    start : str or cftime.datetime, optional
        Left bound for generating dates.
    end : str or cftime.datetime, optional
        Right bound for generating dates.
    periods : int, optional
        Number of periods to generate.
    freq : str or None, default: "D"
        Frequency strings can have multiples, e.g. "5h" and negative values, e.g. "-1D".
    normalize : bool, default: False
        Normalize start/end dates to midnight before generating date range.
    name : str, default: None
        Name of the resulting index
    inclusive : {"both", "neither", "left", "right"}, default "both"
        Include boundaries; whether to set each bound as closed or open.
    calendar : str, default: "standard"
        Calendar type for the datetimes.

    Returns
    -------
    CFTimeIndex

    Notes
    -----
    see cftime_range
    
xarray/coding/cftime_offsets.py