From b17da314e42ea0db4fbb60695e8c8f43334efb9c Mon Sep 17 00:00:00 2001 From: John Liekezer Date: Mon, 8 Aug 2016 01:16:31 +0300 Subject: [PATCH] BUG: Right result for DatetimeIndex + TimeDelta when timezone is set(#13905) --- doc/source/whatsnew/v0.19.0.txt | 1 + pandas/core/ops.py | 6 +++--- pandas/indexes/base.py | 9 ++++++++- pandas/tests/series/test_operators.py | 11 +++++++++++ pandas/types/cast.py | 4 ++-- 5 files changed, 25 insertions(+), 6 deletions(-) diff --git a/doc/source/whatsnew/v0.19.0.txt b/doc/source/whatsnew/v0.19.0.txt index f93e8f4240787..50ab9cd9ba5e5 100644 --- a/doc/source/whatsnew/v0.19.0.txt +++ b/doc/source/whatsnew/v0.19.0.txt @@ -938,6 +938,7 @@ Bug Fixes - Bug in invalid ``Timedelta`` arithmetic and comparison may raise ``ValueError`` rather than ``TypeError`` (:issue:`13624`) - Bug in invalid datetime parsing in ``to_datetime`` and ``DatetimeIndex`` may raise ``TypeError`` rather than ``ValueError`` (:issue:`11169`, :issue:`11287`) - Bug in ``Index`` created with tz-aware ``Timestamp`` and mismatched ``tz`` option incorrectly coerces timezone (:issue:`13692`) +- Bug in ``DatetimeIndex + TimeDelta`` gives wrong results when timezone is set (:issue:`13905`) - Bug in ``DatetimeIndex`` with nanosecond frequency does not include timestamp specified with ``end`` (:issue:`13672`) - Bug in ``Index`` raises ``OutOfBoundsDatetime`` if ``datetime`` exceeds ``datetime64[ns]`` bounds, rather than coercing to ``object`` dtype (:issue:`13663`) diff --git a/pandas/core/ops.py b/pandas/core/ops.py index 44e3be32c23df..73a2a13f733ce 100644 --- a/pandas/core/ops.py +++ b/pandas/core/ops.py @@ -461,7 +461,7 @@ def _convert_to_array(self, values, name=None, other=None): # a datelike elif isinstance(values, pd.DatetimeIndex): - values = values.to_series() + values = values.to_series(True) # datetime with tz elif (isinstance(ovalues, datetime.datetime) and hasattr(ovalues, 'tz')): @@ -543,9 +543,9 @@ def _offset(lvalues, rvalues): # with tz, convert to UTC if self.is_datetime64tz_lhs: - lvalues = lvalues.tz_localize(None) + lvalues = lvalues.tz_convert('UTC') if self.is_datetime64tz_rhs: - rvalues = rvalues.tz_localize(None) + rvalues = rvalues.tz_convert('UTC') lvalues = lvalues.view(np.int64) rvalues = rvalues.view(np.int64) diff --git a/pandas/indexes/base.py b/pandas/indexes/base.py index de7780d25b1e5..aca0c79738ada 100644 --- a/pandas/indexes/base.py +++ b/pandas/indexes/base.py @@ -165,7 +165,14 @@ def __new__(cls, data=None, dtype=None, copy=False, name=None, if (issubclass(data.dtype.type, np.datetime64) or is_datetimetz(data)): from pandas.tseries.index import DatetimeIndex - result = DatetimeIndex(data, copy=copy, name=name, **kwargs) + if 'tz' in kwargs: + tz = kwargs['tz'] + del kwargs['tz'] + result = DatetimeIndex(data, copy=copy, tz='UTC', + name=name, **kwargs).tz_convert(tz) + else: + result = DatetimeIndex(data, copy=copy, + name=name, **kwargs) if dtype is not None and _o_dtype == dtype: return Index(result.to_pydatetime(), dtype=_o_dtype) else: diff --git a/pandas/tests/series/test_operators.py b/pandas/tests/series/test_operators.py index 5ebe528ff8cab..00fccd6ba5333 100644 --- a/pandas/tests/series/test_operators.py +++ b/pandas/tests/series/test_operators.py @@ -373,6 +373,17 @@ def test_timedelta64_operations_with_DateOffset(self): td - op(5) op(5) - td + def test_timedelta64_operations_with_DatetimeIndex_tz(self): + # GH 13905 + dti = pd.DatetimeIndex(['2016-06-28 05:30', '2016-06-28 05:31'], + dtype='datetime64[ns, America/Chicago]') + td = Series(['00:00:05', '00:00:05'], dtype='timedelta64[ns]') + + exp = Series(['2016-06-28 05:30:05-05:00', + '2016-06-28 05:31:05-05:00'], + dtype='datetime64[ns, America/Chicago]') + assert_series_equal(dti + td, exp) + def test_timedelta64_operations_with_timedeltas(self): # td operate with td diff --git a/pandas/types/cast.py b/pandas/types/cast.py index e37b418664ba3..df6223652c7f6 100644 --- a/pandas/types/cast.py +++ b/pandas/types/cast.py @@ -820,8 +820,8 @@ def _possibly_cast_to_datetime(value, dtype, errors='raise'): # input has to be UTC at this point, so just # localize value = to_datetime( - value, - errors=errors).tz_localize(dtype.tz) + value, utc=True, + errors=errors).tz_convert(dtype.tz) elif is_timedelta64: value = to_timedelta(value, errors=errors)._values except (AttributeError, ValueError, TypeError):