diff --git a/doc/source/whatsnew/v0.24.0.rst b/doc/source/whatsnew/v0.24.0.rst index 7fa386935e3f4..2c8f3ad07b639 100644 --- a/doc/source/whatsnew/v0.24.0.rst +++ b/doc/source/whatsnew/v0.24.0.rst @@ -1553,6 +1553,7 @@ Timezones - 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 :meth:`DataFrame.any` returns wrong value when ``axis=1`` and the data is of datetimelike type (:issue:`23070`) +- Bug in :meth:`DatetimeIndex.to_period` where a timezone aware index was converted to UTC first before creating :class:`PeriodIndex` (:issue:`22905`) Offsets ^^^^^^^ @@ -1802,6 +1803,9 @@ Reshaping - Constructing a DataFrame with an index argument that wasn't already an instance of :class:`~pandas.core.Index` was broken (:issue:`22227`). - Bug in :class:`DataFrame` prevented list subclasses to be used to construction (:issue:`21226`) - Bug in :func:`DataFrame.unstack` and :func:`DataFrame.pivot_table` returning a missleading error message when the resulting DataFrame has more elements than int32 can handle. Now, the error message is improved, pointing towards the actual problem (:issue:`20601`) +- Bug in :func:`DataFrame.unstack` where a ``ValueError`` was raised when unstacking timezone aware values (:issue:`18338`) +- Bug in :func:`DataFrame.stack` where timezone aware values were converted to timezone naive values (:issue:`19420`) +- Bug in :func:`merge_asof` where a ``TypeError`` was raised when ``by_col`` were timezone aware values (:issue:`21184`) .. _whatsnew_0240.bug_fixes.sparse: diff --git a/pandas/tests/frame/test_reshape.py b/pandas/tests/frame/test_reshape.py index 362650714418f..f2f6944a21e03 100644 --- a/pandas/tests/frame/test_reshape.py +++ b/pandas/tests/frame/test_reshape.py @@ -936,3 +936,36 @@ def test_unstack_fill_frame_object(): index=list('xyz') ) assert_frame_equal(result, expected) + + +def test_unstack_timezone_aware_values(): + # GH 18338 + df = pd.DataFrame({ + 'timestamp': [ + pd.Timestamp('2017-08-27 01:00:00.709949+0000', tz='UTC')], + 'a': ['a'], + 'b': ['b'], + 'c': ['c'], + }, columns=['timestamp', 'a', 'b', 'c']) + result = df.set_index(['a', 'b']).unstack() + expected = pd.DataFrame([[pd.Timestamp('2017-08-27 01:00:00.709949+0000', + tz='UTC'), + 'c']], + index=pd.Index(['a'], name='a'), + columns=pd.MultiIndex( + levels=[['timestamp', 'c'], ['b']], + codes=[[0, 1], [0, 0]], + names=[None, 'b'])) + assert_frame_equal(result, expected) + + +def test_stack_timezone_aware_values(): + # GH 19420 + ts = pd.date_range(freq="D", start="20180101", end="20180103", + tz="America/New_York") + df = pd.DataFrame({"A": ts}, index=["a", "b", "c"]) + result = df.stack() + expected = pd.Series(ts, + index=pd.MultiIndex(levels=[['a', 'b', 'c'], ['A']], + codes=[[0, 1, 2], [0, 0, 0]])) + assert_series_equal(result, expected) diff --git a/pandas/tests/indexes/datetimes/test_astype.py b/pandas/tests/indexes/datetimes/test_astype.py index c03b8afbe79bf..784d1ca6fb82c 100644 --- a/pandas/tests/indexes/datetimes/test_astype.py +++ b/pandas/tests/indexes/datetimes/test_astype.py @@ -293,6 +293,15 @@ def test_to_period_tz(self, tz): tm.assert_index_equal(result, expected) + @pytest.mark.parametrize('tz', ['Etc/GMT-1', 'Etc/GMT+1']) + def test_to_period_tz_utc_offset_consistency(self, tz): + # GH 22905 + ts = pd.date_range('1/1/2000', '2/1/2000', tz='Etc/GMT-1') + with tm.assert_produces_warning(UserWarning): + result = ts.to_period()[0] + expected = ts[0].to_period() + assert result == expected + def test_to_period_nofreq(self): idx = DatetimeIndex(['2000-01-01', '2000-01-02', '2000-01-04']) with pytest.raises(ValueError): diff --git a/pandas/tests/reshape/merge/test_merge_asof.py b/pandas/tests/reshape/merge/test_merge_asof.py index 1483654daa99e..1d1d7d48adaab 100644 --- a/pandas/tests/reshape/merge/test_merge_asof.py +++ b/pandas/tests/reshape/merge/test_merge_asof.py @@ -1022,3 +1022,17 @@ def test_merge_on_nans(self, func, side): merge_asof(df_null, df, on='a') else: merge_asof(df, df_null, on='a') + + def test_merge_by_col_tz_aware(self): + # GH 21184 + left = pd.DataFrame( + {'by_col': pd.DatetimeIndex(['2018-01-01']).tz_localize('UTC'), + 'on_col': [2], 'values': ['a']}) + right = pd.DataFrame( + {'by_col': pd.DatetimeIndex(['2018-01-01']).tz_localize('UTC'), + 'on_col': [1], 'values': ['b']}) + result = pd.merge_asof(left, right, by='by_col', on='on_col') + expected = pd.DataFrame([ + [pd.Timestamp('2018-01-01', tz='UTC'), 2, 'a', 'b'] + ], columns=['by_col', 'on_col', 'values_x', 'values_y']) + assert_frame_equal(result, expected)