Repository: pandas-dev/pandas
File: pandas/core/algorithms.py (Python)

Code before:
            result = (
                Series(index=values, name=name)
                .groupby(level=levels, dropna=dropna)
                .size()
            )
            result.index.names = values.names
            # error: Incompatible types in assignment (expression has type
            # "ndarray[Any, Any] | DatetimeArray | TimedeltaArray | PeriodArray | Any",
            # variable has type "ndarray[tuple[int, ...], dtype[Any]]")
            counts = result._values  # type: ignore[assignment]

        else:
            values = _ensure_arraylike(values, func_name="value_counts")
            keys, counts, _ = value_counts_arraylike(values, dropna)
            if keys.dtype == np.float16:
                keys = keys.astype(np.float32)

            # Starting in 3.0, we no longer perform dtype inference on the
            #  Index object we construct here, xref GH#56161
            idx = Index(keys, dtype=keys.dtype, name=index_name)

            if (
                bins is None
                and not sort
                and hasattr(values, "freq")
                and values.freq is not None
            ):
                idx = _preserve_freq(values, idx)

            result = Series(counts, index=idx, name=name, copy=False)

    if sort:
        result = result.sort_values(ascending=ascending)

    if normalize:
        result = result / counts.sum()

    return result


# Called once from SparseArray, otherwise could be private
def value_counts_arraylike(
    values: np.ndarray, dropna: bool, mask: npt.NDArray[np.bool_] | None = None
) -> tuple[ArrayLike, npt.NDArray[np.int64], int]:
    """
    Parameters
    ----------
    values : np.ndarray
    dropna : bool
    mask : np.ndarray[bool] or None, default None


Review comment (suggestion):
```suggestion
                and hasattr(values, "freq")
                and values.freq is not None
```

Instead could you `isinstance(values, DatetimeIndex)` (you might need a local import of `DatetimeIndex`). Also you can use `values.inferred_freq` to get the frequency instead

Code after:
            keys, counts, _ = value_counts_arraylike(values, dropna)
            if keys.dtype == np.float16:
                keys = keys.astype(np.float32)

            # Starting in 3.0, we no longer perform dtype inference on the
            #  Index object we construct here, xref GH#56161
            idx = Index(keys, dtype=keys.dtype, name=index_name)

            if (
                bins is None
                and not sort
                and isinstance(values, (DatetimeIndex, TimedeltaIndex))
                and idx.equals(values)
                and values.inferred_freq is not None
            ):
                # Preserve freq of original index
                idx.freq = values.inferred_freq  # type: ignore[attr-defined]

            result = Series(counts, index=idx, name=name, copy=False)

    if sort:
        result = result.sort_values(ascending=ascending)

    if normalize:
        result = result / counts.sum()

    return result


# Called once from SparseArray, otherwise could be private
def value_counts_arraylike(
    values: np.ndarray, dropna: bool, mask: npt.NDArray[np.bool_] | None = None
) -> tuple[ArrayLike, npt.NDArray[np.int64], int]:
    """
    Parameters
    ----------
    values : np.ndarray
    dropna : bool
    mask : np.ndarray[bool] or None, default None

    Returns
    -------
    uniques : np.ndarray
    counts : np.ndarray[np.int64]
    """
    original = values
    values = _ensure_data(values)

    keys, counts, na_counter = htable.value_count(values, dropna, mask=mask)

    if needs_i8_conversion(original.dtype):