diff --git a/pandas/_libs/tslibs/vectorized.pyi b/pandas/_libs/tslibs/vectorized.pyi index 8820a17ce5996..f303d51367ce7 100644 --- a/pandas/_libs/tslibs/vectorized.pyi +++ b/pandas/_libs/tslibs/vectorized.pyi @@ -28,6 +28,7 @@ def normalize_i8_timestamps( def get_resolution( stamps: npt.NDArray[np.int64], tz: tzinfo | None = ..., + reso: int = ..., # NPY_DATETIMEUNIT ) -> Resolution: ... def ints_to_pydatetime( arr: npt.NDArray[np.int64], diff --git a/pandas/_libs/tslibs/vectorized.pyx b/pandas/_libs/tslibs/vectorized.pyx index 2cab55e607f15..4a957e24ccdfd 100644 --- a/pandas/_libs/tslibs/vectorized.pyx +++ b/pandas/_libs/tslibs/vectorized.pyx @@ -33,6 +33,7 @@ from .np_datetime cimport ( NPY_FR_ns, dt64_to_dtstruct, npy_datetimestruct, + pandas_datetime_to_datetimestruct, ) from .offsets cimport BaseOffset from .period cimport get_period_ordinal @@ -226,17 +227,19 @@ cdef inline c_Resolution _reso_stamp(npy_datetimestruct *dts): @cython.wraparound(False) @cython.boundscheck(False) -def get_resolution(ndarray stamps, tzinfo tz=None) -> Resolution: +def get_resolution( + ndarray stamps, tzinfo tz=None, NPY_DATETIMEUNIT reso=NPY_FR_ns +) -> Resolution: # stamps is int64_t, any ndim cdef: - Localizer info = Localizer(tz, reso=NPY_FR_ns) + Localizer info = Localizer(tz, reso=reso) int64_t utc_val, local_val Py_ssize_t i, n = stamps.size Py_ssize_t pos = -1 # unused, avoid not-initialized warning cnp.flatiter it = cnp.PyArray_IterNew(stamps) npy_datetimestruct dts - c_Resolution reso = c_Resolution.RESO_DAY, curr_reso + c_Resolution pd_reso = c_Resolution.RESO_DAY, curr_reso for i in range(n): # Analogous to: utc_val = stamps[i] @@ -247,14 +250,14 @@ def get_resolution(ndarray stamps, tzinfo tz=None) -> Resolution: else: local_val = info.utc_val_to_local_val(utc_val, &pos) - dt64_to_dtstruct(local_val, &dts) + pandas_datetime_to_datetimestruct(local_val, reso, &dts) curr_reso = _reso_stamp(&dts) - if curr_reso < reso: - reso = curr_reso + if curr_reso < pd_reso: + pd_reso = curr_reso cnp.PyArray_ITER_NEXT(it) - return Resolution(reso) + return Resolution(pd_reso) # ------------------------------------------------------------------------- diff --git a/pandas/core/arrays/datetimes.py b/pandas/core/arrays/datetimes.py index db55c165c9974..d297d3e9f8e4e 100644 --- a/pandas/core/arrays/datetimes.py +++ b/pandas/core/arrays/datetimes.py @@ -619,7 +619,7 @@ def is_normalized(self) -> bool: @property # NB: override with cache_readonly in immutable subclasses def _resolution_obj(self) -> Resolution: - return get_resolution(self.asi8, self.tz) + return get_resolution(self.asi8, self.tz, reso=self._reso) # ---------------------------------------------------------------- # Array-Like / EA-Interface Methods diff --git a/pandas/tests/tslibs/test_resolution.py b/pandas/tests/tslibs/test_resolution.py index 15f4a9d032e5c..7b2268f16a85f 100644 --- a/pandas/tests/tslibs/test_resolution.py +++ b/pandas/tests/tslibs/test_resolution.py @@ -1,9 +1,11 @@ import numpy as np +import pytz from pandas._libs.tslibs import ( Resolution, get_resolution, ) +from pandas._libs.tslibs.dtypes import NpyDatetimeUnit def test_get_resolution_nano(): @@ -11,3 +13,12 @@ def test_get_resolution_nano(): arr = np.array([1], dtype=np.int64) res = get_resolution(arr) assert res == Resolution.RESO_NS + + +def test_get_resolution_non_nano_data(): + arr = np.array([1], dtype=np.int64) + res = get_resolution(arr, None, NpyDatetimeUnit.NPY_FR_us.value) + assert res == Resolution.RESO_US + + res = get_resolution(arr, pytz.UTC, NpyDatetimeUnit.NPY_FR_us.value) + assert res == Resolution.RESO_US diff --git a/setup.py b/setup.py index cb713e6d74392..27e6d8cb10025 100755 --- a/setup.py +++ b/setup.py @@ -551,7 +551,11 @@ def srcpath(name=None, suffix=".pyx", subdir="src"): "depends": tseries_depends, "sources": ["pandas/_libs/tslibs/src/datetime/np_datetime.c"], }, - "_libs.tslibs.vectorized": {"pyxfile": "_libs/tslibs/vectorized"}, + "_libs.tslibs.vectorized": { + "pyxfile": "_libs/tslibs/vectorized", + "depends": tseries_depends, + "sources": ["pandas/_libs/tslibs/src/datetime/np_datetime.c"], + }, "_libs.testing": {"pyxfile": "_libs/testing"}, "_libs.window.aggregations": { "pyxfile": "_libs/window/aggregations",