diff --git a/doc/source/whatsnew/v0.23.2.txt b/doc/source/whatsnew/v0.23.2.txt index c636e73fbd6c2..c03065bc7e63d 100644 --- a/doc/source/whatsnew/v0.23.2.txt +++ b/doc/source/whatsnew/v0.23.2.txt @@ -75,4 +75,4 @@ Bug Fixes **Other** -- +- Timestamp resolution returns a :class:`Timedelta` (in nanoseconds) rather than a normal `timedelta` object (in microseconds) (:issue:`21336`) diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.txt index 68c1839221508..e0c476870c37f 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -193,4 +193,3 @@ Other - :meth: `~pandas.io.formats.style.Styler.background_gradient` now takes a ``text_color_threshold`` parameter to automatically lighten the text color based on the luminance of the background color. This improves readability with dark background colors without the need to limit the background colormap range. (:issue:`21258`) - - -- diff --git a/pandas/_libs/tslibs/timedeltas.pyx b/pandas/_libs/tslibs/timedeltas.pyx index 87dc371195b5b..91c90263b0f43 100644 --- a/pandas/_libs/tslibs/timedeltas.pyx +++ b/pandas/_libs/tslibs/timedeltas.pyx @@ -795,7 +795,11 @@ cdef class _Timedelta(timedelta): @property def resolution(self): - """ return a string representing the lowest resolution that we have """ + """ + Return a string representing the lowest resolution that we have. + Note that this is nonstandard behavior. + To retrieve a timedelta object use the resolution_timedelta property + """ self._ensure_components() if self._ns: @@ -813,6 +817,32 @@ cdef class _Timedelta(timedelta): else: return "D" + @property + def resolution_timedelta(self): + """ + Return a timedelta object (rather than a string) + representing the lowest resolution we have. + to retrieve a string use the resolution property. + """ + + self._ensure_components() + if self._ns: + # At time of writing datetime.timedelta doesn't + # support nanoseconds as a keyword argument. + return timedelta(microseconds=0.1) + elif self._us: + return timedelta(microseconds=1) + elif self._ms: + return timedelta(milliseconds=1) + elif self._s: + return timedelta(seconds=1) + elif self._m: + return timedelta(minutes=1) + elif self._h: + return timedelta(hours=1) + else: + return timedelta(days=1) + @property def nanoseconds(self): """ diff --git a/pandas/_libs/tslibs/timestamps.pyx b/pandas/_libs/tslibs/timestamps.pyx index ba5ebdab82ddc..fcf9e8583c9fc 100644 --- a/pandas/_libs/tslibs/timestamps.pyx +++ b/pandas/_libs/tslibs/timestamps.pyx @@ -400,12 +400,17 @@ cdef class _Timestamp(datetime): def asm8(self): return np.datetime64(self.value, 'ns') + @property + def resolution(self): + """ Return resolution in a native pandas format. """ + # GH 21336 + return Timedelta(nanoseconds=1) + def timestamp(self): """Return POSIX timestamp as float.""" # py27 compat, see GH#17329 return round(self.value / 1e9, 6) - # ---------------------------------------------------------------------- # Python front end to C extension type _Timestamp diff --git a/pandas/tests/scalar/timedelta/test_timedelta.py b/pandas/tests/scalar/timedelta/test_timedelta.py index 205fdf49d3e91..509de841b7730 100644 --- a/pandas/tests/scalar/timedelta/test_timedelta.py +++ b/pandas/tests/scalar/timedelta/test_timedelta.py @@ -588,3 +588,31 @@ def test_components(self): result = s.dt.components assert not result.iloc[0].isna().all() assert result.iloc[1].isna().all() + + def test_resolution(self): + # GH 21344 + assert Timedelta(nanoseconds=30).resolution == 'N' + # Note that datetime.timedelta doesn't offer + # finer resolution than microseconds + assert Timedelta(nanoseconds=30).resolution_timedelta.resolution == \ + timedelta(0, 0, 1) + + assert Timedelta(microseconds=30).resolution == 'U' + assert Timedelta(microseconds=30).resolution_timedelta.resolution == \ + timedelta(0, 0, 1) + + assert Timedelta(milliseconds=30).resolution == 'L' + assert Timedelta(milliseconds=30).resolution_timedelta.resolution == \ + timedelta(0, 0, 1) + + assert Timedelta(seconds=30).resolution == 'S' + assert Timedelta(seconds=30).resolution_timedelta.resolution == \ + timedelta(0, 0, 1) + + assert Timedelta(minutes=30).resolution == 'T' + assert Timedelta(minutes=30).resolution_timedelta.resolution == \ + timedelta(0, 0, 1) + + assert Timedelta(hours=2).resolution == 'H' + assert Timedelta(hours=2).resolution_timedelta.resolution == \ + timedelta(0, 0, 1) diff --git a/pandas/tests/scalar/timestamp/test_timestamp.py b/pandas/tests/scalar/timestamp/test_timestamp.py index ab87d98fca8eb..4681531ff55d5 100644 --- a/pandas/tests/scalar/timestamp/test_timestamp.py +++ b/pandas/tests/scalar/timestamp/test_timestamp.py @@ -172,6 +172,11 @@ def test_woy_boundary(self): 2005, 1, 1), (2005, 1, 2)]]) assert (result == [52, 52, 53, 53]).all() + def test_resolution(self): + # GH 21336 + dt = Timestamp('2100-01-01 00:00:00') + assert dt.resolution == Timedelta(nanoseconds=1) + class TestTimestampConstructors(object):