diff --git a/pandas/_libs/tslibs/vectorized.pyx b/pandas/_libs/tslibs/vectorized.pyx index 39bcfc9277969..6b78100705a93 100644 --- a/pandas/_libs/tslibs/vectorized.pyx +++ b/pandas/_libs/tslibs/vectorized.pyx @@ -80,20 +80,31 @@ cdef class Localizer: else: trans, deltas, typ = get_dst_info(tz) self.trans = trans - self.ntrans = trans.shape[0] + self.ntrans = self.trans.shape[0] self.deltas = deltas if typ != "pytz" and typ != "dateutil": # static/fixed; in this case we know that len(delta) == 1 self.use_fixed = True - self.delta = deltas[0] + self.delta = self.deltas[0] else: self.use_dst = True if typ == "pytz": self.use_pytz = True - self.tdata = cnp.PyArray_DATA(self.trans) + @cython.boundscheck(False) + cdef inline int64_t utc_val_to_local_val(self, int64_t utc_val, Py_ssize_t* pos) except? -1: + if self.use_utc: + return utc_val + elif self.use_tzlocal: + return utc_val + localize_tzinfo_api(utc_val, self.tz) + elif self.use_fixed: + return utc_val + self.delta + else: + pos[0] = bisect_right_i8(self.tdata, utc_val, self.ntrans) - 1 + return utc_val + self.deltas[pos[0]] + @cython.boundscheck(False) @cython.wraparound(False) @@ -186,7 +197,8 @@ def ints_to_pydatetime( cdef: Localizer info = Localizer(tz) int64_t utc_val, local_val - Py_ssize_t pos, i, n = stamps.shape[0] + Py_ssize_t i, n = stamps.shape[0] + Py_ssize_t pos = -1 # unused, avoid not-initialized warning npy_datetimestruct dts tzinfo new_tz @@ -215,19 +227,10 @@ def ints_to_pydatetime( result[i] = NaT continue - 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(info.tdata, utc_val, info.ntrans) - 1 - local_val = utc_val + info.deltas[pos] - - if info.use_pytz: - # find right representation of dst etc in pytz timezone - new_tz = tz._tzinfos[tz._transition_info[pos]] + local_val = info.utc_val_to_local_val(utc_val, &pos) + if info.use_pytz: + # find right representation of dst etc in pytz timezone + new_tz = tz._tzinfos[tz._transition_info[pos]] dt64_to_dtstruct(local_val, &dts) @@ -269,7 +272,8 @@ def get_resolution(const int64_t[:] stamps, tzinfo tz=None) -> Resolution: cdef: Localizer info = Localizer(tz) int64_t utc_val, local_val - Py_ssize_t pos, i, n = stamps.shape[0] + Py_ssize_t i, n = stamps.shape[0] + Py_ssize_t pos = -1 # unused, avoid not-initialized warning npy_datetimestruct dts c_Resolution reso = c_Resolution.RESO_DAY, curr_reso @@ -279,15 +283,7 @@ def get_resolution(const int64_t[:] stamps, tzinfo tz=None) -> Resolution: if utc_val == NPY_NAT: continue - 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(info.tdata, utc_val, info.ntrans) - 1 - local_val = utc_val + info.deltas[pos] + local_val = info.utc_val_to_local_val(utc_val, &pos) dt64_to_dtstruct(local_val, &dts) curr_reso = _reso_stamp(&dts) @@ -321,7 +317,8 @@ cpdef ndarray[int64_t] normalize_i8_timestamps(const int64_t[:] stamps, tzinfo t cdef: Localizer info = Localizer(tz) int64_t utc_val, local_val - Py_ssize_t pos, i, n = stamps.shape[0] + Py_ssize_t i, n = stamps.shape[0] + Py_ssize_t pos = -1 # unused, avoid not-initialized warning int64_t[::1] result = np.empty(n, dtype=np.int64) @@ -331,15 +328,7 @@ cpdef ndarray[int64_t] normalize_i8_timestamps(const int64_t[:] stamps, tzinfo t result[i] = NPY_NAT continue - 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(info.tdata, utc_val, info.ntrans) - 1 - local_val = utc_val + info.deltas[pos] + local_val = info.utc_val_to_local_val(utc_val, &pos) result[i] = local_val - (local_val % DAY_NANOS) @@ -366,19 +355,12 @@ def is_date_array_normalized(const int64_t[:] stamps, tzinfo tz=None) -> bool: cdef: Localizer info = Localizer(tz) int64_t utc_val, local_val - Py_ssize_t pos, i, n = stamps.shape[0] + Py_ssize_t i, n = stamps.shape[0] + Py_ssize_t pos = -1 # unused, avoid not-initialized warning for i in range(n): utc_val = stamps[i] - 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(info.tdata, utc_val, info.ntrans) - 1 - local_val = utc_val + info.deltas[pos] + local_val = info.utc_val_to_local_val(utc_val, &pos) if local_val % DAY_NANOS != 0: return False @@ -395,7 +377,8 @@ def dt64arr_to_periodarr(ndarray stamps, int freq, tzinfo tz): # stamps is int64_t, arbitrary ndim cdef: Localizer info = Localizer(tz) - Py_ssize_t pos, i, n = stamps.size + Py_ssize_t i, n = stamps.size + Py_ssize_t pos = -1 # unused, avoid not-initialized warning int64_t utc_val, local_val, res_val npy_datetimestruct dts @@ -409,16 +392,7 @@ def dt64arr_to_periodarr(ndarray stamps, int freq, tzinfo tz): if utc_val == NPY_NAT: res_val = NPY_NAT else: - 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(info.tdata, utc_val, info.ntrans) - 1 - local_val = utc_val + info.deltas[pos] - + local_val = info.utc_val_to_local_val(utc_val, &pos) dt64_to_dtstruct(local_val, &dts) res_val = get_period_ordinal(&dts, freq)