diff --git a/pandas/_libs/tslibs/vectorized.pyx b/pandas/_libs/tslibs/vectorized.pyx index 5829bf5492ef8..0f0e321b2d5bf 100644 --- a/pandas/_libs/tslibs/vectorized.pyx +++ b/pandas/_libs/tslibs/vectorized.pyx @@ -355,36 +355,44 @@ def is_date_array_normalized(const int64_t[:] stamps, tzinfo tz=None) -> bool: @cython.wraparound(False) @cython.boundscheck(False) -def dt64arr_to_periodarr(const int64_t[:] stamps, int freq, tzinfo tz): +def dt64arr_to_periodarr(ndarray stamps, int freq, tzinfo tz): + # stamps is int64_t, arbitrary ndim cdef: Localizer info = Localizer(tz) - int64_t utc_val, local_val - Py_ssize_t pos, i, n = stamps.shape[0] + Py_ssize_t pos, i, n = stamps.size + int64_t utc_val, local_val, res_val int64_t* tdata = NULL npy_datetimestruct dts - int64_t[::1] result = np.empty(n, dtype=np.int64) + ndarray result = cnp.PyArray_EMPTY(stamps.ndim, stamps.shape, cnp.NPY_INT64, 0) + cnp.broadcast mi = cnp.PyArray_MultiIterNew2(result, stamps) if info.use_dst: tdata = cnp.PyArray_DATA(info.trans) for i in range(n): - utc_val = stamps[i] - if utc_val == NPY_NAT: - result[i] = NPY_NAT - continue + # Analogous to: utc_val = stamps[i] + utc_val = (cnp.PyArray_MultiIter_DATA(mi, 1))[0] - if info.use_utc: - local_val = utc_val - elif info.use_tzlocal: - local_val = utc_val + localize_tzinfo_api(utc_val, tz) - elif info.use_fixed: - local_val = utc_val + info.delta + if utc_val == NPY_NAT: + res_val = NPY_NAT else: - pos = bisect_right_i8(tdata, utc_val, info.ntrans) - 1 - local_val = utc_val + info.deltas[pos] + if info.use_utc: + local_val = utc_val + elif info.use_tzlocal: + local_val = utc_val + localize_tzinfo_api(utc_val, tz) + elif info.use_fixed: + local_val = utc_val + info.delta + else: + pos = bisect_right_i8(tdata, utc_val, info.ntrans) - 1 + local_val = utc_val + info.deltas[pos] - dt64_to_dtstruct(local_val, &dts) - result[i] = get_period_ordinal(&dts, freq) + dt64_to_dtstruct(local_val, &dts) + res_val = get_period_ordinal(&dts, freq) + + # Analogous to: result[i] = res_val + (cnp.PyArray_MultiIter_DATA(mi, 0))[0] = res_val - return result.base # .base to get underlying ndarray + cnp.PyArray_MultiIter_NEXT(mi) + + return result diff --git a/pandas/core/arrays/datetimes.py b/pandas/core/arrays/datetimes.py index 667a7b6ed4ae1..98ea2af57465b 100644 --- a/pandas/core/arrays/datetimes.py +++ b/pandas/core/arrays/datetimes.py @@ -1124,7 +1124,6 @@ def normalize(self) -> DatetimeArray: new_values = normalize_i8_timestamps(self.asi8, self.tz) return type(self)(new_values)._with_freq("infer").tz_localize(self.tz) - @dtl.ravel_compat def to_period(self, freq=None) -> PeriodArray: """ Cast to PeriodArray/Index at a particular frequency.