From cadd955a32152dc7675832424845d4505599f489 Mon Sep 17 00:00:00 2001 From: Drew Massey Date: Thu, 7 Jun 2018 14:43:55 -0400 Subject: [PATCH 01/10] Override default resolution property from date-time object (with unit test) --- pandas/_libs/tslibs/timestamps.pyx | 7 +++++++ pandas/tests/scalar/timestamp/test_timestamp.py | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/pandas/_libs/tslibs/timestamps.pyx b/pandas/_libs/tslibs/timestamps.pyx index ba5ebdab82ddc..d1c9478edb2c4 100644 --- a/pandas/_libs/tslibs/timestamps.pyx +++ b/pandas/_libs/tslibs/timestamps.pyx @@ -400,12 +400,19 @@ 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/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): From 5fdfd9e32446e3259f2b4f468086aedc8cc074a1 Mon Sep 17 00:00:00 2001 From: Drew Massey Date: Thu, 7 Jun 2018 14:48:24 -0400 Subject: [PATCH 02/10] Called out changes on this PR in docs. --- doc/source/whatsnew/v0.23.1.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/whatsnew/v0.23.1.txt b/doc/source/whatsnew/v0.23.1.txt index 9c29c34adb7dd..417800bc0b397 100644 --- a/doc/source/whatsnew/v0.23.1.txt +++ b/doc/source/whatsnew/v0.23.1.txt @@ -116,3 +116,4 @@ Other - Tab completion on :class:`Index` in IPython no longer outputs deprecation warnings (:issue:`21125`) - Bug preventing pandas from being importable with -OO optimization (:issue:`21071`) +- Timestamp resolution returns a :class:`Timedelta` rather than a normal `timedelta` object (:issue:`21336`) \ No newline at end of file From 544e8349a2bef04f4ed28fff8e3d9be4c70c790f Mon Sep 17 00:00:00 2001 From: Drew Massey Date: Thu, 7 Jun 2018 16:39:49 -0400 Subject: [PATCH 03/10] Added Function --- pandas/_libs/tslibs/timedeltas.pyx | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/pandas/_libs/tslibs/timedeltas.pyx b/pandas/_libs/tslibs/timedeltas.pyx index 87dc371195b5b..9d1c075db178d 100644 --- a/pandas/_libs/tslibs/timedeltas.pyx +++ b/pandas/_libs/tslibs/timedeltas.pyx @@ -795,11 +795,14 @@ 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: - return "N" + return elif self._us: return "U" elif self._ms: @@ -813,6 +816,28 @@ 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 retireve a string use the resolution property. + """ + self._ensure_components() + if self._ns: + return timedelta(nanoseconds=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): """ From a72e4348ba7cf2e1b8434cdd420935f2b9b4de98 Mon Sep 17 00:00:00 2001 From: Drew Massey Date: Thu, 7 Jun 2018 16:42:15 -0400 Subject: [PATCH 04/10] Incorporated Linting feedback --- pandas/_libs/tslibs/timestamps.pyx | 3 --- 1 file changed, 3 deletions(-) diff --git a/pandas/_libs/tslibs/timestamps.pyx b/pandas/_libs/tslibs/timestamps.pyx index d1c9478edb2c4..db641a97a6932 100644 --- a/pandas/_libs/tslibs/timestamps.pyx +++ b/pandas/_libs/tslibs/timestamps.pyx @@ -411,14 +411,11 @@ cdef class _Timestamp(datetime): # py27 compat, see GH#17329 return round(self.value / 1e9, 6) - - # ---------------------------------------------------------------------- # Python front end to C extension type _Timestamp # This serves as the box for datetime64 - class Timestamp(_Timestamp): """Pandas replacement for datetime.datetime From b7caafbf0e92554bf70482d7edc2c3710c2ba9d3 Mon Sep 17 00:00:00 2001 From: Drew Massey Date: Thu, 7 Jun 2018 17:09:27 -0400 Subject: [PATCH 05/10] Fixed linting issue --- pandas/_libs/tslibs/timestamps.pyx | 1 + 1 file changed, 1 insertion(+) diff --git a/pandas/_libs/tslibs/timestamps.pyx b/pandas/_libs/tslibs/timestamps.pyx index db641a97a6932..fcf9e8583c9fc 100644 --- a/pandas/_libs/tslibs/timestamps.pyx +++ b/pandas/_libs/tslibs/timestamps.pyx @@ -416,6 +416,7 @@ cdef class _Timestamp(datetime): # Python front end to C extension type _Timestamp # This serves as the box for datetime64 + class Timestamp(_Timestamp): """Pandas replacement for datetime.datetime From c53f2c2e56eefb7501b5146da5c71c248422a7a9 Mon Sep 17 00:00:00 2001 From: Drew Massey Date: Fri, 8 Jun 2018 11:21:03 -0400 Subject: [PATCH 06/10] Clarified 'Whats New' Language --- doc/source/whatsnew/v0.23.1.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v0.23.1.txt b/doc/source/whatsnew/v0.23.1.txt index 4491897277e38..ca6d87560bf5e 100644 --- a/doc/source/whatsnew/v0.23.1.txt +++ b/doc/source/whatsnew/v0.23.1.txt @@ -119,4 +119,4 @@ Other - Tab completion on :class:`Index` in IPython no longer outputs deprecation warnings (:issue:`21125`) - Bug preventing pandas from being importable with -OO optimization (:issue:`21071`) -- Timestamp resolution returns a :class:`Timedelta` rather than a normal `timedelta` object (:issue:`21336`) \ No newline at end of file +- Timestamp resolution returns a :class:`Timedelta` (in nanoseconds) rather than a normal `timedelta` object (in microseconds) (:issue:`21336`) \ No newline at end of file From 75e4a855fb71ce998c01aa6bb83436f8691b74a8 Mon Sep 17 00:00:00 2001 From: Drew Massey Date: Tue, 12 Jun 2018 11:36:42 -0400 Subject: [PATCH 07/10] Timedelta resolution update --- pandas/_libs/tslibs/timedeltas.pyx | 23 +++++++++------ .../tests/scalar/timedelta/test_timedelta.py | 28 +++++++++++++++++++ 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/pandas/_libs/tslibs/timedeltas.pyx b/pandas/_libs/tslibs/timedeltas.pyx index 9d1c075db178d..91c90263b0f43 100644 --- a/pandas/_libs/tslibs/timedeltas.pyx +++ b/pandas/_libs/tslibs/timedeltas.pyx @@ -795,14 +795,15 @@ cdef class _Timedelta(timedelta): @property def resolution(self): - """ 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 + """ + 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: - return + return "N" elif self._us: return "U" elif self._ms: @@ -818,13 +819,17 @@ cdef class _Timedelta(timedelta): @property def resolution_timedelta(self): - """ return a timedelta object (rather than a string) - representing the lowest resolution we have. - to retireve a string use the resolution property. """ + 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: - return timedelta(nanoseconds=1) + # 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: @@ -836,7 +841,7 @@ cdef class _Timedelta(timedelta): elif self._h: return timedelta(hours=1) else: - return timedelta(days=1) + return timedelta(days=1) @property def nanoseconds(self): 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) From 1c63c2abc7c7ff1e8c5dfb6dc0202157d8d18b1f Mon Sep 17 00:00:00 2001 From: Drew Massey Date: Tue, 12 Jun 2018 11:44:36 -0400 Subject: [PATCH 08/10] Updated what's new --- doc/source/whatsnew/v0.23.1.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/whatsnew/v0.23.1.txt b/doc/source/whatsnew/v0.23.1.txt index db25bcf8113f5..51dcb324f538c 100644 --- a/doc/source/whatsnew/v0.23.1.txt +++ b/doc/source/whatsnew/v0.23.1.txt @@ -133,3 +133,4 @@ Bug Fixes - Tab completion on :class:`Index` in IPython no longer outputs deprecation warnings (:issue:`21125`) - Bug preventing pandas being used on Windows without C++ redistributable installed (:issue:`21106`) +- Add `resolution_timedelta` to :class:`Timedelta` to get non-string representations of resolution (:issue: `21344`) From 0e9e4618caf1eff35162aae4b6b1b9c3881a4540 Mon Sep 17 00:00:00 2001 From: Drew Massey Date: Tue, 12 Jun 2018 14:08:29 -0400 Subject: [PATCH 09/10] Updated What's new --- doc/source/whatsnew/v0.23.1.txt | 2 -- doc/source/whatsnew/v0.24.0.txt | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/doc/source/whatsnew/v0.23.1.txt b/doc/source/whatsnew/v0.23.1.txt index ba7cfa31db9bc..db25bcf8113f5 100644 --- a/doc/source/whatsnew/v0.23.1.txt +++ b/doc/source/whatsnew/v0.23.1.txt @@ -132,6 +132,4 @@ Bug Fixes **Other** - Tab completion on :class:`Index` in IPython no longer outputs deprecation warnings (:issue:`21125`) -- Timestamp resolution returns a :class:`Timedelta` (in nanoseconds) rather than a normal `timedelta` object (in microseconds) (:issue:`21336`) - Bug preventing pandas being used on Windows without C++ redistributable installed (:issue:`21106`) -- Add `resolution_timedelta` to :class:`Timedelta` to get non-string representations of resolution (:issue: `21344`) diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.txt index 68c1839221508..b732809e8169a 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -191,6 +191,7 @@ 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`) -- +- Timestamp resolution returns a :class:`Timedelta` (in nanoseconds) rather than a normal `timedelta` object (in microseconds) (:issue:`21336`) + - - From f28dc5def4d8c32b0935c58a7654c455db3c13cb Mon Sep 17 00:00:00 2001 From: Drew Massey Date: Tue, 12 Jun 2018 14:11:26 -0400 Subject: [PATCH 10/10] Updated what's new --- doc/source/whatsnew/v0.23.2.txt | 2 +- doc/source/whatsnew/v0.24.0.txt | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) 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 b732809e8169a..e0c476870c37f 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -191,7 +191,5 @@ 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`) -- Timestamp resolution returns a :class:`Timedelta` (in nanoseconds) rather than a normal `timedelta` object (in microseconds) (:issue:`21336`) - - -