From 234b33ab6f05f0cd015336a50ed63029674c6032 Mon Sep 17 00:00:00 2001 From: Brock Date: Tue, 10 May 2022 10:34:03 -0700 Subject: [PATCH 1/3] ENH: Timestamp.timestamp non-nano --- pandas/_libs/tslibs/dtypes.pxd | 1 + pandas/_libs/tslibs/dtypes.pyx | 13 +++++++++++++ pandas/_libs/tslibs/timestamps.pyx | 11 +++++++---- pandas/tests/scalar/timestamp/test_timestamp.py | 4 ++++ 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/pandas/_libs/tslibs/dtypes.pxd b/pandas/_libs/tslibs/dtypes.pxd index 8cc7bcb2a1aad..833ba4ce70bd7 100644 --- a/pandas/_libs/tslibs/dtypes.pxd +++ b/pandas/_libs/tslibs/dtypes.pxd @@ -6,6 +6,7 @@ from pandas._libs.tslibs.np_datetime cimport NPY_DATETIMEUNIT cdef str npy_unit_to_abbrev(NPY_DATETIMEUNIT unit) cdef NPY_DATETIMEUNIT freq_group_code_to_npy_unit(int freq) nogil cdef int64_t periods_per_day(NPY_DATETIMEUNIT reso=*) except? -1 +cdef int64_t periods_per_second(NPY_DATETIMEUNIT reso) except? -1 cdef dict attrname_to_abbrevs diff --git a/pandas/_libs/tslibs/dtypes.pyx b/pandas/_libs/tslibs/dtypes.pyx index 0c4d4c5c235b5..3be21ba754f27 100644 --- a/pandas/_libs/tslibs/dtypes.pyx +++ b/pandas/_libs/tslibs/dtypes.pyx @@ -348,6 +348,19 @@ cdef int64_t periods_per_day(NPY_DATETIMEUNIT reso=NPY_DATETIMEUNIT.NPY_FR_ns) e return day_units +cdef int64_t periods_per_second(NPY_DATETIMEUNIT reso) except? -1: + if reso == NPY_DATETIMEUNIT.NPY_FR_ns: + return 1_000_000_000 + elif reso == NPY_DATETIMEUNIT.NPY_FR_us: + return 1_000_000 + elif reso == NPY_DATETIMEUNIT.NPY_FR_ms: + return 1_000 + elif reso == NPY_DATETIMEUNIT.NPY_FR_s: + return 1 + else: + raise NotImplementedError(reso) + + cdef dict _reso_str_map = { Resolution.RESO_NS.value: "nanosecond", Resolution.RESO_US.value: "microsecond", diff --git a/pandas/_libs/tslibs/timestamps.pyx b/pandas/_libs/tslibs/timestamps.pyx index 923d1f830e1a9..2e3839492e08b 100644 --- a/pandas/_libs/tslibs/timestamps.pyx +++ b/pandas/_libs/tslibs/timestamps.pyx @@ -52,7 +52,10 @@ from pandas._libs.tslibs.conversion cimport ( convert_datetime_to_tsobject, convert_to_tsobject, ) -from pandas._libs.tslibs.dtypes cimport npy_unit_to_abbrev +from pandas._libs.tslibs.dtypes cimport ( + npy_unit_to_abbrev, + periods_per_second, +) from pandas._libs.tslibs.util cimport ( is_array, is_datetime64_object, @@ -982,10 +985,10 @@ cdef class _Timestamp(ABCTimestamp): """ # GH 17329 # Note: Naive timestamps will not match datetime.stdlib - if self._reso != NPY_FR_ns: - raise NotImplementedError(self._reso) - return round(self.value / 1e9, 6) + denom = periods_per_second(self._reso) + + return round(self.value / denom, 6) cpdef datetime to_pydatetime(_Timestamp self, bint warn=True): """ diff --git a/pandas/tests/scalar/timestamp/test_timestamp.py b/pandas/tests/scalar/timestamp/test_timestamp.py index c892816629462..e9f4482046a50 100644 --- a/pandas/tests/scalar/timestamp/test_timestamp.py +++ b/pandas/tests/scalar/timestamp/test_timestamp.py @@ -840,3 +840,7 @@ def test_to_datetime64(self, dt64, ts): res = ts.to_datetime64() assert res == dt64 assert res.dtype == dt64.dtype + + def test_timestamp(self, dt64, ts): + alt = Timestamp(dt64) + assert ts.timestamp() == alt.timestamp() From 470eee1d10a4b414229312caf0f3bccae10e5abc Mon Sep 17 00:00:00 2001 From: Brock Date: Tue, 10 May 2022 10:45:32 -0700 Subject: [PATCH 2/3] ENH: Timestamp.to_period non-nano --- pandas/_libs/tslibs/timestamps.pyx | 3 --- pandas/tests/scalar/timestamp/test_timestamp.py | 4 ++++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/pandas/_libs/tslibs/timestamps.pyx b/pandas/_libs/tslibs/timestamps.pyx index 2e3839492e08b..059407bf265c1 100644 --- a/pandas/_libs/tslibs/timestamps.pyx +++ b/pandas/_libs/tslibs/timestamps.pyx @@ -1083,9 +1083,6 @@ cdef class _Timestamp(ABCTimestamp): """ from pandas import Period - if self._reso != NPY_FR_ns: - raise NotImplementedError(self._reso) - if self.tz is not None: # GH#21333 warnings.warn( diff --git a/pandas/tests/scalar/timestamp/test_timestamp.py b/pandas/tests/scalar/timestamp/test_timestamp.py index e9f4482046a50..108d58bcc251d 100644 --- a/pandas/tests/scalar/timestamp/test_timestamp.py +++ b/pandas/tests/scalar/timestamp/test_timestamp.py @@ -844,3 +844,7 @@ def test_to_datetime64(self, dt64, ts): def test_timestamp(self, dt64, ts): alt = Timestamp(dt64) assert ts.timestamp() == alt.timestamp() + + def test_to_period(self, dt64, ts): + alt = Timestamp(dt64) + assert ts.to_period("D") == alt.to_period("D") From e42a3bbe5f0273718131127aec298086221c7add Mon Sep 17 00:00:00 2001 From: Brock Date: Tue, 10 May 2022 14:54:57 -0700 Subject: [PATCH 3/3] normalize prelims --- pandas/_libs/tslibs/timestamps.pyx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/pandas/_libs/tslibs/timestamps.pyx b/pandas/_libs/tslibs/timestamps.pyx index 059407bf265c1..fcc9390a2cccd 100644 --- a/pandas/_libs/tslibs/timestamps.pyx +++ b/pandas/_libs/tslibs/timestamps.pyx @@ -54,6 +54,7 @@ from pandas._libs.tslibs.conversion cimport ( ) from pandas._libs.tslibs.dtypes cimport ( npy_unit_to_abbrev, + periods_per_day, periods_per_second, ) from pandas._libs.tslibs.util cimport ( @@ -814,11 +815,12 @@ cdef class _Timestamp(ABCTimestamp): cdef: local_val = self._maybe_convert_value_to_local() int64_t normalized + int64_t ppd = periods_per_day(self._reso) if self._reso != NPY_FR_ns: raise NotImplementedError(self._reso) - normalized = normalize_i8_stamp(local_val) + normalized = normalize_i8_stamp(local_val, ppd) return Timestamp(normalized).tz_localize(self.tzinfo) # ----------------------------------------------------------------- @@ -837,8 +839,8 @@ cdef class _Timestamp(ABCTimestamp): if len(state) == 3: # pre-non-nano pickle + # TODO: no tests get here 2022-05-10 reso = NPY_FR_ns - assert False # checking for coverage else: reso = state[4] self._reso = reso @@ -2252,16 +2254,18 @@ Timestamp.resolution = Timedelta(nanoseconds=1) # GH#21336, GH#21365 @cython.cdivision(False) -cdef inline int64_t normalize_i8_stamp(int64_t local_val) nogil: +cdef inline int64_t normalize_i8_stamp(int64_t local_val, int64_t ppd) nogil: """ Round the localized nanosecond timestamp down to the previous midnight. Parameters ---------- local_val : int64_t + ppd : int64_t + Periods per day in the Timestamp's resolution. Returns ------- int64_t """ - return local_val - (local_val % ccalendar.DAY_NANOS) + return local_val - (local_val % ppd)