From 120e12dad5d91875534108f8060a195e4f0eee95 Mon Sep 17 00:00:00 2001 From: Matt Roeschke Date: Tue, 29 Aug 2017 23:16:00 -0700 Subject: [PATCH 1/6] BUG: Return local Timestamp.weekday_name attribute (#17354) --- pandas/_libs/tslib.pyx | 16 ++++++++++++---- pandas/tests/scalar/test_timestamp.py | 8 ++++++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/pandas/_libs/tslib.pyx b/pandas/_libs/tslib.pyx index 50e0b77c6d3a0..d2755e3c5f46e 100644 --- a/pandas/_libs/tslib.pyx +++ b/pandas/_libs/tslib.pyx @@ -532,9 +532,7 @@ class Timestamp(_Timestamp): @property def weekday_name(self): - out = get_date_name_field( - np.array([self.value], dtype=np.int64), 'weekday_name') - return out[0] + return self._get_named_field('weekday_name') @property def dayofyear(self): @@ -1268,13 +1266,23 @@ cdef class _Timestamp(datetime): # same timezone if specified) return datetime.__sub__(self, other) - cpdef _get_field(self, field): + cpdef _maybe_convert_value_to_local(self): + """Convert UTC i8 value to local i8 value if tz exists" val = self.value if self.tz is not None and not _is_utc(self.tz): val = tz_convert_single(self.value, 'UTC', self.tz) + return val + + cpdef _get_field(self, field): + val = self._maybe_convert_value_to_local() out = get_date_field(np.array([val], dtype=np.int64), field) return int(out[0]) + cpdef _get_named_field(self, field): + val = self._maybe_convert_value_to_local() + out = get_date_name_field(np.array([val], dtype=np.int64), field) + return out[0] + cpdef _get_start_end_field(self, field): month_kw = self.freq.kwds.get( 'startingMonth', self.freq.kwds.get( diff --git a/pandas/tests/scalar/test_timestamp.py b/pandas/tests/scalar/test_timestamp.py index 7cd1a7db0f9fe..8d47ce4802ac6 100644 --- a/pandas/tests/scalar/test_timestamp.py +++ b/pandas/tests/scalar/test_timestamp.py @@ -555,6 +555,14 @@ def check(value, equal): for end in ends: assert getattr(ts, end) + @pytest.mark.parametrize('data, expected', + [(Timestamp('2017-08-28 23:00:00'), 'Monday'), + (Timestamp('2017-08-28 23:00:00', tz='EST'), + 'Monday')]) + def test_weekday_name(self, data, expected): + # GH 17354 + assert data.weekday_name == expected + def test_pprint(self): # GH12622 import pprint From fb4095adb6bad563f3437c7f7a2ead1b997b9288 Mon Sep 17 00:00:00 2001 From: Matt Roeschke Date: Tue, 29 Aug 2017 23:21:21 -0700 Subject: [PATCH 2/6] Add whatsnew --- doc/source/whatsnew/v0.21.0.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/whatsnew/v0.21.0.txt b/doc/source/whatsnew/v0.21.0.txt index 81e52266f972e..d18be88aea509 100644 --- a/doc/source/whatsnew/v0.21.0.txt +++ b/doc/source/whatsnew/v0.21.0.txt @@ -399,6 +399,7 @@ Conversion - Fixed the return type of ``IntervalIndex.is_non_overlapping_monotonic`` to be a Python ``bool`` for consistency with similar attributes/methods. Previously returned a ``numpy.bool_``. (:issue:`17237`) - Bug in ``IntervalIndex.is_non_overlapping_monotonic`` when intervals are closed on both sides and overlap at a point (:issue:`16560`) - Bug in :func:`Series.fillna` returns frame when ``inplace=True`` and ``value`` is dict (:issue:`16156`) +- Bug in ``Timestamp.weekday_name`` returning a UTC-based weekday name when localized to a timezone (:issue:`17354`) Indexing ^^^^^^^^ From e453d10a71c47d948522a5be55fa8360b8a7d0a3 Mon Sep 17 00:00:00 2001 From: Matt Roeschke Date: Thu, 31 Aug 2017 21:52:02 -0700 Subject: [PATCH 3/6] Type ctype variables and functions, whatsnew fix --- doc/source/whatsnew/v0.21.0.txt | 2 +- pandas/_libs/tslib.pyx | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/doc/source/whatsnew/v0.21.0.txt b/doc/source/whatsnew/v0.21.0.txt index d18be88aea509..14e07978c7adc 100644 --- a/doc/source/whatsnew/v0.21.0.txt +++ b/doc/source/whatsnew/v0.21.0.txt @@ -399,7 +399,7 @@ Conversion - Fixed the return type of ``IntervalIndex.is_non_overlapping_monotonic`` to be a Python ``bool`` for consistency with similar attributes/methods. Previously returned a ``numpy.bool_``. (:issue:`17237`) - Bug in ``IntervalIndex.is_non_overlapping_monotonic`` when intervals are closed on both sides and overlap at a point (:issue:`16560`) - Bug in :func:`Series.fillna` returns frame when ``inplace=True`` and ``value`` is dict (:issue:`16156`) -- Bug in ``Timestamp.weekday_name`` returning a UTC-based weekday name when localized to a timezone (:issue:`17354`) +- Bug in :attr:`Timestamp.weekday_name` returning a UTC-based weekday name when localized to a timezone (:issue:`17354`) Indexing ^^^^^^^^ diff --git a/pandas/_libs/tslib.pyx b/pandas/_libs/tslib.pyx index d2755e3c5f46e..342d9f2fb7102 100644 --- a/pandas/_libs/tslib.pyx +++ b/pandas/_libs/tslib.pyx @@ -1266,7 +1266,7 @@ cdef class _Timestamp(datetime): # same timezone if specified) return datetime.__sub__(self, other) - cpdef _maybe_convert_value_to_local(self): + cdef int64_t _maybe_convert_value_to_local(self): """Convert UTC i8 value to local i8 value if tz exists" val = self.value if self.tz is not None and not _is_utc(self.tz): @@ -1274,11 +1274,15 @@ cdef class _Timestamp(datetime): return val cpdef _get_field(self, field): + cdef: + int64_t val val = self._maybe_convert_value_to_local() out = get_date_field(np.array([val], dtype=np.int64), field) return int(out[0]) cpdef _get_named_field(self, field): + cdef: + int64_t val val = self._maybe_convert_value_to_local() out = get_date_name_field(np.array([val], dtype=np.int64), field) return out[0] From 18852f4eab7a76dfb624ff0ae64314a61cfcbf91 Mon Sep 17 00:00:00 2001 From: Matt Roeschke Date: Fri, 1 Sep 2017 12:10:25 -0700 Subject: [PATCH 4/6] Balance triple quotes --- pandas/_libs/tslib.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/_libs/tslib.pyx b/pandas/_libs/tslib.pyx index 342d9f2fb7102..727724577d97a 100644 --- a/pandas/_libs/tslib.pyx +++ b/pandas/_libs/tslib.pyx @@ -1267,7 +1267,7 @@ cdef class _Timestamp(datetime): return datetime.__sub__(self, other) cdef int64_t _maybe_convert_value_to_local(self): - """Convert UTC i8 value to local i8 value if tz exists" + """Convert UTC i8 value to local i8 value if tz exists""" val = self.value if self.tz is not None and not _is_utc(self.tz): val = tz_convert_single(self.value, 'UTC', self.tz) From 9d0031f1be1656e14bb14801fbfff3a47442143d Mon Sep 17 00:00:00 2001 From: Matt Roeschke Date: Tue, 5 Sep 2017 21:45:54 -0700 Subject: [PATCH 5/6] Ctype array and leftover val --- pandas/_libs/tslib.pyx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/pandas/_libs/tslib.pyx b/pandas/_libs/tslib.pyx index 727724577d97a..8628cd396524e 100644 --- a/pandas/_libs/tslib.pyx +++ b/pandas/_libs/tslib.pyx @@ -1268,6 +1268,8 @@ cdef class _Timestamp(datetime): cdef int64_t _maybe_convert_value_to_local(self): """Convert UTC i8 value to local i8 value if tz exists""" + cdef: + int64_t val val = self.value if self.tz is not None and not _is_utc(self.tz): val = tz_convert_single(self.value, 'UTC', self.tz) @@ -1276,15 +1278,19 @@ cdef class _Timestamp(datetime): cpdef _get_field(self, field): cdef: int64_t val + ndarray[int64_t] date_array = np.empty(1, dtype=np.int64) val = self._maybe_convert_value_to_local() - out = get_date_field(np.array([val], dtype=np.int64), field) + date_array[0] = val + out = get_date_field(date_array, field) return int(out[0]) cpdef _get_named_field(self, field): cdef: int64_t val + ndarray[int64_t] date_array = np.empty(1, dtype=np.int64) val = self._maybe_convert_value_to_local() - out = get_date_name_field(np.array([val], dtype=np.int64), field) + date_array[0] = val + out = get_date_name_field(date_array, field) return out[0] cpdef _get_start_end_field(self, field): From ddaa4e39e530562a37b6ba80598c7d777000710e Mon Sep 17 00:00:00 2001 From: Matt Roeschke Date: Wed, 6 Sep 2017 08:13:48 -0700 Subject: [PATCH 6/6] untype array --- pandas/_libs/tslib.pyx | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/pandas/_libs/tslib.pyx b/pandas/_libs/tslib.pyx index 8628cd396524e..40b473e6ff85f 100644 --- a/pandas/_libs/tslib.pyx +++ b/pandas/_libs/tslib.pyx @@ -1278,19 +1278,15 @@ cdef class _Timestamp(datetime): cpdef _get_field(self, field): cdef: int64_t val - ndarray[int64_t] date_array = np.empty(1, dtype=np.int64) val = self._maybe_convert_value_to_local() - date_array[0] = val - out = get_date_field(date_array, field) + out = get_date_field(np.array([val], dtype=np.int64), field) return int(out[0]) cpdef _get_named_field(self, field): cdef: int64_t val - ndarray[int64_t] date_array = np.empty(1, dtype=np.int64) val = self._maybe_convert_value_to_local() - date_array[0] = val - out = get_date_name_field(date_array, field) + out = get_date_name_field(np.array([val], dtype=np.int64), field) return out[0] cpdef _get_start_end_field(self, field):