diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.txt index 406ca9ba045c9..1105acda067d3 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -164,12 +164,6 @@ Datetimelike ^^^^^^^^^^^^ - Fixed bug where two :class:`DateOffset` objects with different ``normalize`` attributes could evaluate as equal (:issue:`21404`) -- Bug in :class:`Index` with ``datetime64[ns, tz]`` dtype that did not localize integer data correctly (:issue:`20964`) -- Bug in :meth:`DatetimeIndex.shift` where an ``AssertionError`` would raise when shifting across DST (:issue:`8616`) -- Bug in :class:`Timestamp` constructor where passing an invalid timezone offset designator (``Z``) would not raise a ``ValueError``(:issue:`8910`) -- Bug in :meth:`Timestamp.replace` where replacing at a DST boundary would retain an incorrect offset (:issue:`7825`) -- Bug in :meth:`DatetimeIndex.reindex` when reindexing a tz-naive and tz-aware :class:`DatetimeIndex` (:issue:`8306`) -- Bug in :meth:`DatetimeIndex.resample` when downsampling across a DST boundary (:issue:`8531`) Timedelta ^^^^^^^^^ @@ -181,9 +175,15 @@ Timedelta Timezones ^^^^^^^^^ -- -- -- +- Bug in :meth:`DatetimeIndex.shift` where an ``AssertionError`` would raise when shifting across DST (:issue:`8616`) +- Bug in :class:`Timestamp` constructor where passing an invalid timezone offset designator (``Z``) would not raise a ``ValueError``(:issue:`8910`) +- Bug in :meth:`Timestamp.replace` where replacing at a DST boundary would retain an incorrect offset (:issue:`7825`) +- Bug in :meth:`Series.replace` with ``datetime64[ns, tz]`` data when replacing ``NaT`` (:issue:`11792`) +- Bug in :class:`Timestamp` when passing different string date formats with a timezone offset would produce different timezone offsets (:issue:`12064`) +- Bug when comparing a tz-naive :class:`Timestamp` to a tz-aware :class:`DatetimeIndex` which would coerce the :class:`DatetimeIndex` to tz-naive (:issue:`12601`) +- Bug in :meth:`Series.truncate` with a tz-aware :class:`DatetimeIndex` which would cause a core dump (:issue:`9243`) +- Bug in :class:`Series` constructor which would coerce tz-aware and tz-naive :class:`Timestamp`s to tz-aware (:issue:`13051`) +- Bug in :class:`Index` with ``datetime64[ns, tz]`` dtype that did not localize integer data correctly (:issue:`20964`) Offsets ^^^^^^^ @@ -217,7 +217,10 @@ Indexing - The traceback from a ``KeyError`` when asking ``.loc`` for a single missing label is now shorter and more clear (:issue:`21557`) - When ``.ix`` is asked for a missing integer label in a :class:`MultiIndex` with a first level of integer type, it now raises a ``KeyError`` - consistently with the case of a flat :class:`Int64Index` - rather than falling back to positional indexing (:issue:`21593`) -- +- Bug in :meth:`DatetimeIndex.reindex` when reindexing a tz-naive and tz-aware :class:`DatetimeIndex` (:issue:`8306`) +- Bug in :class:`DataFrame` when setting values with ``.loc`` and a timezone aware :class:`DatetimeIndex` (:issue:`11365`) +- Bug when indexing :class:`DatetimeIndex` with nanosecond resolution dates and timezones (:issue:`11679`) + - MultiIndex @@ -245,6 +248,7 @@ Groupby/Resample/Rolling ^^^^^^^^^^^^^^^^^^^^^^^^ - Bug in :func:`pandas.core.groupby.GroupBy.first` and :func:`pandas.core.groupby.GroupBy.last` with ``as_index=False`` leading to the loss of timezone information (:issue:`15884`) +- Bug in :meth:`DatetimeIndex.resample` when downsampling across a DST boundary (:issue:`8531`) - - diff --git a/pandas/conftest.py b/pandas/conftest.py index 803b3add97052..ae08e0817de29 100644 --- a/pandas/conftest.py +++ b/pandas/conftest.py @@ -320,3 +320,20 @@ def mock(): return importlib.import_module("unittest.mock") else: return pytest.importorskip("mock") + + +@pytest.fixture(params=['__eq__', '__ne__', '__le__', + '__lt__', '__ge__', '__gt__']) +def all_compare_operators(request): + """ + Fixture for dunder names for common compare operations + + * >= + * > + * == + * != + * < + * <= + """ + + return request.param diff --git a/pandas/tests/frame/test_indexing.py b/pandas/tests/frame/test_indexing.py index be37e696ea0a3..c7aaf900b17fa 100644 --- a/pandas/tests/frame/test_indexing.py +++ b/pandas/tests/frame/test_indexing.py @@ -2248,6 +2248,16 @@ def test_setitem_datetimelike_with_inference(self): index=list('ABCDEFGH')) assert_series_equal(result, expected) + @pytest.mark.parametrize('idxer', ['var', ['var']]) + def test_setitem_datetimeindex_tz(self, idxer, tz_naive_fixture): + # GH 11365 + tz = tz_naive_fixture + idx = date_range(start='2015-07-12', periods=3, freq='H', tz=tz) + expected = DataFrame(1.2, index=idx, columns=['var']) + result = DataFrame(index=idx, columns=['var']) + result.loc[:, idxer] = expected + tm.assert_frame_equal(result, expected) + def test_at_time_between_time_datetimeindex(self): index = date_range("2012-01-01", "2012-01-05", freq='30min') df = DataFrame(randn(len(index), 5), index=index) diff --git a/pandas/tests/indexes/datetimes/test_arithmetic.py b/pandas/tests/indexes/datetimes/test_arithmetic.py index 0649083a440df..ff31ffee13217 100644 --- a/pandas/tests/indexes/datetimes/test_arithmetic.py +++ b/pandas/tests/indexes/datetimes/test_arithmetic.py @@ -276,6 +276,10 @@ def test_comparison_tzawareness_compat(self, op): with pytest.raises(TypeError): op(dz, ts) + # GH 12601: Check comparison against Timestamps and DatetimeIndex + with pytest.raises(TypeError): + op(ts, dz) + @pytest.mark.parametrize('op', [operator.eq, operator.ne, operator.gt, operator.ge, operator.lt, operator.le]) diff --git a/pandas/tests/indexes/datetimes/test_date_range.py b/pandas/tests/indexes/datetimes/test_date_range.py index ec37bbbcb6c02..47d4d15420f1d 100644 --- a/pandas/tests/indexes/datetimes/test_date_range.py +++ b/pandas/tests/indexes/datetimes/test_date_range.py @@ -292,6 +292,15 @@ def test_construct_over_dst(self): freq='H', tz='US/Pacific') tm.assert_index_equal(result, expected) + def test_construct_with_different_start_end_string_format(self): + # GH 12064 + result = date_range('2013-01-01 00:00:00+09:00', + '2013/01/01 02:00:00+09:00', freq='H') + expected = DatetimeIndex([Timestamp('2013-01-01 00:00:00+09:00'), + Timestamp('2013-01-01 01:00:00+09:00'), + Timestamp('2013-01-01 02:00:00+09:00')]) + tm.assert_index_equal(result, expected) + class TestGenRangeGeneration(object): diff --git a/pandas/tests/indexing/test_datetime.py b/pandas/tests/indexing/test_datetime.py index a5c12e4152c90..751372380d262 100644 --- a/pandas/tests/indexing/test_datetime.py +++ b/pandas/tests/indexing/test_datetime.py @@ -252,3 +252,17 @@ def test_series_partial_set_period(self): check_stacklevel=False): result = ser.loc[keys] tm.assert_series_equal(result, exp) + + def test_nanosecond_getitem_setitem_with_tz(self): + # GH 11679 + data = ['2016-06-28 08:30:00.123456789'] + index = pd.DatetimeIndex(data, dtype='datetime64[ns, America/Chicago]') + df = DataFrame({'a': [10]}, index=index) + result = df.loc[df.index[0]] + expected = Series(10, index=['a'], name=df.index[0]) + tm.assert_series_equal(result, expected) + + result = df.copy() + result.loc[df.index[0], 'a'] = -1 + expected = DataFrame(-1, index=index, columns=['a']) + tm.assert_frame_equal(result, expected) diff --git a/pandas/tests/scalar/timestamp/test_timestamp.py b/pandas/tests/scalar/timestamp/test_timestamp.py index 8dc9903b7356d..5272059163a07 100644 --- a/pandas/tests/scalar/timestamp/test_timestamp.py +++ b/pandas/tests/scalar/timestamp/test_timestamp.py @@ -542,6 +542,14 @@ def test_construct_timestamp_near_dst(self, offset): result = Timestamp(expected, tz='Europe/Helsinki') assert result == expected + @pytest.mark.parametrize('arg', [ + '2013/01/01 00:00:00+09:00', '2013-01-01 00:00:00+09:00']) + def test_construct_with_different_string_format(self, arg): + # GH 12064 + result = Timestamp(arg) + expected = Timestamp(datetime(2013, 1, 1), tz=pytz.FixedOffset(540)) + assert result == expected + class TestTimestamp(object): diff --git a/pandas/tests/series/test_constructors.py b/pandas/tests/series/test_constructors.py index 27cfec0dbf20d..fe224436c52e6 100644 --- a/pandas/tests/series/test_constructors.py +++ b/pandas/tests/series/test_constructors.py @@ -1185,3 +1185,11 @@ def test_constructor_range_dtype(self, dtype): expected = Series([0, 1, 2, 3, 4], dtype=dtype or 'int64') result = Series(range(5), dtype=dtype) tm.assert_series_equal(result, expected) + + def test_constructor_tz_mixed_data(self): + # GH 13051 + dt_list = [Timestamp('2016-05-01 02:03:37'), + Timestamp('2016-04-30 19:03:37-0700', tz='US/Pacific')] + result = Series(dt_list) + expected = Series(dt_list, dtype=object) + tm.assert_series_equal(result, expected) diff --git a/pandas/tests/series/test_replace.py b/pandas/tests/series/test_replace.py index 2c07d87865f53..a3b92798879f5 100644 --- a/pandas/tests/series/test_replace.py +++ b/pandas/tests/series/test_replace.py @@ -108,6 +108,13 @@ def test_replace_gh5319(self): pd.Timestamp('20120101')) tm.assert_series_equal(result, expected) + # GH 11792: Test with replacing NaT in a list with tz data + ts = pd.Timestamp('2015/01/01', tz='UTC') + s = pd.Series([pd.NaT, pd.Timestamp('2015/01/01', tz='UTC')]) + result = s.replace([np.nan, pd.NaT], pd.Timestamp.min) + expected = pd.Series([pd.Timestamp.min, ts], dtype=object) + tm.assert_series_equal(expected, result) + def test_replace_with_single_list(self): ser = pd.Series([0, 1, 2, 3, 4]) result = ser.replace([1, 2, 3]) diff --git a/pandas/tests/series/test_timezones.py b/pandas/tests/series/test_timezones.py index b54645d04bd1a..f2433163352ac 100644 --- a/pandas/tests/series/test_timezones.py +++ b/pandas/tests/series/test_timezones.py @@ -300,3 +300,11 @@ def test_getitem_pydatetime_tz(self, tzstr): dt = datetime(2012, 12, 24, 17, 0) time_datetime = tslib._localize_pydatetime(dt, tz) assert ts[time_pandas] == ts[time_datetime] + + def test_series_truncate_datetimeindex_tz(self): + # GH 9243 + idx = date_range('4/1/2005', '4/30/2005', freq='D', tz='US/Pacific') + s = Series(range(len(idx)), index=idx) + result = s.truncate(datetime(2005, 4, 2), datetime(2005, 4, 4)) + expected = Series([1, 2, 3], index=idx[1:4]) + tm.assert_series_equal(result, expected)