Skip to content

Commit d49a244

Browse files
authored
ENH: non-nano Timestamp.timestamp, to_period (#46990)
* ENH: Timestamp.timestamp non-nano * ENH: Timestamp.to_period non-nano * normalize prelims
1 parent c22bc65 commit d49a244

File tree

4 files changed

+37
-11
lines changed

4 files changed

+37
-11
lines changed

pandas/_libs/tslibs/dtypes.pxd

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ from pandas._libs.tslibs.np_datetime cimport NPY_DATETIMEUNIT
66
cdef str npy_unit_to_abbrev(NPY_DATETIMEUNIT unit)
77
cdef NPY_DATETIMEUNIT freq_group_code_to_npy_unit(int freq) nogil
88
cdef int64_t periods_per_day(NPY_DATETIMEUNIT reso=*) except? -1
9+
cdef int64_t periods_per_second(NPY_DATETIMEUNIT reso) except? -1
910

1011
cdef dict attrname_to_abbrevs
1112

pandas/_libs/tslibs/dtypes.pyx

+13
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,19 @@ cdef int64_t periods_per_day(NPY_DATETIMEUNIT reso=NPY_DATETIMEUNIT.NPY_FR_ns) e
348348
return day_units
349349

350350

351+
cdef int64_t periods_per_second(NPY_DATETIMEUNIT reso) except? -1:
352+
if reso == NPY_DATETIMEUNIT.NPY_FR_ns:
353+
return 1_000_000_000
354+
elif reso == NPY_DATETIMEUNIT.NPY_FR_us:
355+
return 1_000_000
356+
elif reso == NPY_DATETIMEUNIT.NPY_FR_ms:
357+
return 1_000
358+
elif reso == NPY_DATETIMEUNIT.NPY_FR_s:
359+
return 1
360+
else:
361+
raise NotImplementedError(reso)
362+
363+
351364
cdef dict _reso_str_map = {
352365
Resolution.RESO_NS.value: "nanosecond",
353366
Resolution.RESO_US.value: "microsecond",

pandas/_libs/tslibs/timestamps.pyx

+15-11
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,11 @@ from pandas._libs.tslibs.conversion cimport (
5252
convert_datetime_to_tsobject,
5353
convert_to_tsobject,
5454
)
55-
from pandas._libs.tslibs.dtypes cimport npy_unit_to_abbrev
55+
from pandas._libs.tslibs.dtypes cimport (
56+
npy_unit_to_abbrev,
57+
periods_per_day,
58+
periods_per_second,
59+
)
5660
from pandas._libs.tslibs.util cimport (
5761
is_array,
5862
is_datetime64_object,
@@ -811,11 +815,12 @@ cdef class _Timestamp(ABCTimestamp):
811815
cdef:
812816
local_val = self._maybe_convert_value_to_local()
813817
int64_t normalized
818+
int64_t ppd = periods_per_day(self._reso)
814819

815820
if self._reso != NPY_FR_ns:
816821
raise NotImplementedError(self._reso)
817822

818-
normalized = normalize_i8_stamp(local_val)
823+
normalized = normalize_i8_stamp(local_val, ppd)
819824
return Timestamp(normalized).tz_localize(self.tzinfo)
820825

821826
# -----------------------------------------------------------------
@@ -834,8 +839,8 @@ cdef class _Timestamp(ABCTimestamp):
834839

835840
if len(state) == 3:
836841
# pre-non-nano pickle
842+
# TODO: no tests get here 2022-05-10
837843
reso = NPY_FR_ns
838-
assert False # checking for coverage
839844
else:
840845
reso = state[4]
841846
self._reso = reso
@@ -982,10 +987,10 @@ cdef class _Timestamp(ABCTimestamp):
982987
"""
983988
# GH 17329
984989
# Note: Naive timestamps will not match datetime.stdlib
985-
if self._reso != NPY_FR_ns:
986-
raise NotImplementedError(self._reso)
987990

988-
return round(self.value / 1e9, 6)
991+
denom = periods_per_second(self._reso)
992+
993+
return round(self.value / denom, 6)
989994

990995
cpdef datetime to_pydatetime(_Timestamp self, bint warn=True):
991996
"""
@@ -1080,9 +1085,6 @@ cdef class _Timestamp(ABCTimestamp):
10801085
"""
10811086
from pandas import Period
10821087

1083-
if self._reso != NPY_FR_ns:
1084-
raise NotImplementedError(self._reso)
1085-
10861088
if self.tz is not None:
10871089
# GH#21333
10881090
warnings.warn(
@@ -2252,16 +2254,18 @@ Timestamp.resolution = Timedelta(nanoseconds=1) # GH#21336, GH#21365
22522254

22532255

22542256
@cython.cdivision(False)
2255-
cdef inline int64_t normalize_i8_stamp(int64_t local_val) nogil:
2257+
cdef inline int64_t normalize_i8_stamp(int64_t local_val, int64_t ppd) nogil:
22562258
"""
22572259
Round the localized nanosecond timestamp down to the previous midnight.
22582260
22592261
Parameters
22602262
----------
22612263
local_val : int64_t
2264+
ppd : int64_t
2265+
Periods per day in the Timestamp's resolution.
22622266
22632267
Returns
22642268
-------
22652269
int64_t
22662270
"""
2267-
return local_val - (local_val % ccalendar.DAY_NANOS)
2271+
return local_val - (local_val % ppd)

pandas/tests/scalar/timestamp/test_timestamp.py

+8
Original file line numberDiff line numberDiff line change
@@ -840,3 +840,11 @@ def test_to_datetime64(self, dt64, ts):
840840
res = ts.to_datetime64()
841841
assert res == dt64
842842
assert res.dtype == dt64.dtype
843+
844+
def test_timestamp(self, dt64, ts):
845+
alt = Timestamp(dt64)
846+
assert ts.timestamp() == alt.timestamp()
847+
848+
def test_to_period(self, dt64, ts):
849+
alt = Timestamp(dt64)
850+
assert ts.to_period("D") == alt.to_period("D")

0 commit comments

Comments
 (0)