From d29eeba7c31ec265b07f090c580ee6d318d94051 Mon Sep 17 00:00:00 2001 From: Matt Roeschke Date: Wed, 26 Dec 2018 12:17:09 -0800 Subject: [PATCH 1/4] BUG: to_datetime(Timestamp, utc=True) localizes to UTC --- doc/source/whatsnew/v0.24.0.rst | 1 + pandas/core/tools/datetimes.py | 2 ++ pandas/tests/indexes/datetimes/test_tools.py | 12 ++++++++++++ 3 files changed, 15 insertions(+) diff --git a/doc/source/whatsnew/v0.24.0.rst b/doc/source/whatsnew/v0.24.0.rst index d12d929470be5..19052c9eebff0 100644 --- a/doc/source/whatsnew/v0.24.0.rst +++ b/doc/source/whatsnew/v0.24.0.rst @@ -1368,6 +1368,7 @@ Timezones - Bug in :meth:`DatetimeIndex.tz_localize` and :meth:`Timestamp.tz_localize` with ``dateutil.tz.tzlocal`` near a DST transition that would return an incorrectly localized datetime (:issue:`23807`) - Bug in :class:`Timestamp` constructor where a ``dateutil.tz.tzutc`` timezone passed with a ``datetime.datetime`` argument would be converted to a ``pytz.UTC`` timezone (:issue:`23807`) - Bug in :func:`to_datetime` where ``utc=True`` was not respected when specifying a ``unit`` and ``errors='ignore'`` (:issue:`23758`) +- bug in :func:`to_datetime` where ``utc=True`` was not respected when passing a :class:`Timestamp` (:issue:`24415`) Offsets ^^^^^^^ diff --git a/pandas/core/tools/datetimes.py b/pandas/core/tools/datetimes.py index 4df6f4c661d43..f00227fc375f8 100644 --- a/pandas/core/tools/datetimes.py +++ b/pandas/core/tools/datetimes.py @@ -568,6 +568,8 @@ def to_datetime(arg, errors='raise', dayfirst=False, yearfirst=False, if isinstance(arg, Timestamp): result = arg + if tz is not None: + result = arg.tz_localize(tz) elif isinstance(arg, ABCSeries): cache_array = _maybe_cache(arg, format, cache, convert_listlike) if not cache_array.empty: diff --git a/pandas/tests/indexes/datetimes/test_tools.py b/pandas/tests/indexes/datetimes/test_tools.py index 0abcf597f7212..36e1a2d66fbba 100644 --- a/pandas/tests/indexes/datetimes/test_tools.py +++ b/pandas/tests/indexes/datetimes/test_tools.py @@ -655,6 +655,18 @@ def test_non_iso_strings_with_tz_offset(self): tzinfo=pytz.FixedOffset(240))] * 2) tm.assert_index_equal(result, expected) + def test_timestamp_utc_true(self): + # GH 24415 + ts = Timestamp(2018, 1, 1) + result = to_datetime(ts, utc=True) + expected = ts.tz_localize('UTC') + assert result == expected + + msg = ('Cannot localize tz-aware Timestamp, use tz_convert for ' + 'conversions') + with pytest.raises(TypeError, match=msg): + to_datetime(ts.tz_localize('US/Pacific'), utc=True) + class TestToDatetimeUnit(object): @pytest.mark.parametrize('cache', [True, False]) From 071882484d24b1ad17865dc7cbf52aa310080ebf Mon Sep 17 00:00:00 2001 From: Matt Roeschke Date: Wed, 26 Dec 2018 12:19:55 -0800 Subject: [PATCH 2/4] capitalize Bug in whatsnew --- doc/source/whatsnew/v0.24.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v0.24.0.rst b/doc/source/whatsnew/v0.24.0.rst index 19052c9eebff0..df6c131489726 100644 --- a/doc/source/whatsnew/v0.24.0.rst +++ b/doc/source/whatsnew/v0.24.0.rst @@ -1368,7 +1368,7 @@ Timezones - Bug in :meth:`DatetimeIndex.tz_localize` and :meth:`Timestamp.tz_localize` with ``dateutil.tz.tzlocal`` near a DST transition that would return an incorrectly localized datetime (:issue:`23807`) - Bug in :class:`Timestamp` constructor where a ``dateutil.tz.tzutc`` timezone passed with a ``datetime.datetime`` argument would be converted to a ``pytz.UTC`` timezone (:issue:`23807`) - Bug in :func:`to_datetime` where ``utc=True`` was not respected when specifying a ``unit`` and ``errors='ignore'`` (:issue:`23758`) -- bug in :func:`to_datetime` where ``utc=True`` was not respected when passing a :class:`Timestamp` (:issue:`24415`) +- Bug in :func:`to_datetime` where ``utc=True`` was not respected when passing a :class:`Timestamp` (:issue:`24415`) Offsets ^^^^^^^ From 081fded990df919a875e19e7f2496c176c953cfd Mon Sep 17 00:00:00 2001 From: Matt Roeschke Date: Wed, 26 Dec 2018 13:51:33 -0800 Subject: [PATCH 3/4] allow tz-aware timestamp to be converted --- pandas/core/tools/datetimes.py | 5 ++++- pandas/tests/indexes/datetimes/test_tools.py | 8 ++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/pandas/core/tools/datetimes.py b/pandas/core/tools/datetimes.py index f00227fc375f8..69d735d7fdc65 100644 --- a/pandas/core/tools/datetimes.py +++ b/pandas/core/tools/datetimes.py @@ -569,7 +569,10 @@ def to_datetime(arg, errors='raise', dayfirst=False, yearfirst=False, if isinstance(arg, Timestamp): result = arg if tz is not None: - result = arg.tz_localize(tz) + if arg.tz is not None: + result = result.tz_convert(tz) + else: + result = result.tz_localize(tz) elif isinstance(arg, ABCSeries): cache_array = _maybe_cache(arg, format, cache, convert_listlike) if not cache_array.empty: diff --git a/pandas/tests/indexes/datetimes/test_tools.py b/pandas/tests/indexes/datetimes/test_tools.py index 36e1a2d66fbba..b26657448a316 100644 --- a/pandas/tests/indexes/datetimes/test_tools.py +++ b/pandas/tests/indexes/datetimes/test_tools.py @@ -662,10 +662,10 @@ def test_timestamp_utc_true(self): expected = ts.tz_localize('UTC') assert result == expected - msg = ('Cannot localize tz-aware Timestamp, use tz_convert for ' - 'conversions') - with pytest.raises(TypeError, match=msg): - to_datetime(ts.tz_localize('US/Pacific'), utc=True) + ts = ts.tz_localize('US/Pacific') + result = to_datetime(ts, utc=True) + expected = ts.tz_convert('UTC') + assert result == expected class TestToDatetimeUnit(object): From d4a4a075ad752ba2325d86177b965ef8bc5befb3 Mon Sep 17 00:00:00 2001 From: Matt Roeschke Date: Wed, 26 Dec 2018 14:59:11 -0800 Subject: [PATCH 4/4] parametrize test --- pandas/tests/indexes/datetimes/test_tools.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/pandas/tests/indexes/datetimes/test_tools.py b/pandas/tests/indexes/datetimes/test_tools.py index b26657448a316..530da1a625af4 100644 --- a/pandas/tests/indexes/datetimes/test_tools.py +++ b/pandas/tests/indexes/datetimes/test_tools.py @@ -655,16 +655,14 @@ def test_non_iso_strings_with_tz_offset(self): tzinfo=pytz.FixedOffset(240))] * 2) tm.assert_index_equal(result, expected) - def test_timestamp_utc_true(self): + @pytest.mark.parametrize('ts, expected', [ + (Timestamp('2018-01-01'), + Timestamp('2018-01-01', tz='UTC')), + (Timestamp('2018-01-01', tz='US/Pacific'), + Timestamp('2018-01-01 08:00', tz='UTC'))]) + def test_timestamp_utc_true(self, ts, expected): # GH 24415 - ts = Timestamp(2018, 1, 1) result = to_datetime(ts, utc=True) - expected = ts.tz_localize('UTC') - assert result == expected - - ts = ts.tz_localize('US/Pacific') - result = to_datetime(ts, utc=True) - expected = ts.tz_convert('UTC') assert result == expected