Skip to content

Commit

Permalink
BUG: Timestamp == date match stdlib (pandas-dev#36131)
Browse files Browse the repository at this point in the history
  • Loading branch information
jbrockmendel authored and luckyvs1 committed Jan 20, 2021
1 parent a538f63 commit 965d58e
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 1 deletion.
1 change: 1 addition & 0 deletions doc/source/whatsnew/v1.3.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ Deprecations
- Deprecated allowing subclass-specific keyword arguments in the :class:`Index` constructor, use the specific subclass directly instead (:issue:`14093`,:issue:`21311`,:issue:`22315`,:issue:`26974`)
- Deprecated ``astype`` of datetimelike (``timedelta64[ns]``, ``datetime64[ns]``, ``Datetime64TZDtype``, ``PeriodDtype``) to integer dtypes, use ``values.view(...)`` instead (:issue:`38544`)
- Deprecated keyword ``try_cast`` in :meth:`Series.where`, :meth:`Series.mask`, :meth:`DataFrame.where`, :meth:`DataFrame.mask`; cast results manually if desired (:issue:`38836`)
- Deprecated comparison of :class:`Timestamp` object with ``datetime.date`` objects. Instead of e.g. ``ts <= mydate`` use ``ts <= pd.Timestamp(mydate)`` or ``ts.date() <= mydate`` (:issue:`36131`)
-

.. ---------------------------------------------------------------------------
Expand Down
15 changes: 15 additions & 0 deletions pandas/_libs/tslibs/timestamps.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ from numpy cimport int8_t, int64_t, ndarray, uint8_t
cnp.import_array()

from cpython.datetime cimport ( # alias bc `tzinfo` is a kwarg below
PyDate_Check,
PyDateTime_Check,
PyDateTime_IMPORT,
PyDelta_Check,
Expand Down Expand Up @@ -281,6 +282,20 @@ cdef class _Timestamp(ABCTimestamp):
return np.zeros(other.shape, dtype=np.bool_)
return NotImplemented

elif PyDate_Check(other):
# returning NotImplemented defers to the `date` implementation
# which incorrectly drops tz and normalizes to midnight
# before comparing
# We follow the stdlib datetime behavior of never being equal
warnings.warn(
"Comparison of Timestamp with datetime.date is deprecated in "
"order to match the standard library behavior. "
"In a future version these will be considered non-comparable."
"Use 'ts == pd.Timestamp(date)' or 'ts.date() == date' instead.",
FutureWarning,
stacklevel=1,
)
return NotImplemented
else:
return NotImplemented

Expand Down
5 changes: 4 additions & 1 deletion pandas/tests/frame/indexing/test_indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -1429,7 +1429,10 @@ def test_loc_setitem_datetime_coercion(self):
assert Timestamp("2008-08-08") == df.loc[0, "c"]
assert Timestamp("2008-08-08") == df.loc[1, "c"]
df.loc[2, "c"] = date(2005, 5, 5)
assert Timestamp("2005-05-05") == df.loc[2, "c"]
with tm.assert_produces_warning(FutureWarning):
# Comparing Timestamp to date obj is deprecated
assert Timestamp("2005-05-05") == df.loc[2, "c"]
assert Timestamp("2005-05-05").date() == df.loc[2, "c"]

def test_loc_setitem_datetimelike_with_inference(self):
# GH 7592
Expand Down
5 changes: 5 additions & 0 deletions pandas/tests/indexes/datetimes/test_indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -613,8 +613,13 @@ def test_get_indexer_mixed_dtypes(self, target):
([date(9999, 1, 1), date(9999, 1, 1)], [-1, -1]),
],
)
# FIXME: these warnings are flaky GH#36131
@pytest.mark.filterwarnings(
"ignore:Comparison of Timestamp with datetime.date:FutureWarning"
)
def test_get_indexer_out_of_bounds_date(self, target, positions):
values = DatetimeIndex([Timestamp("2020-01-01"), Timestamp("2020-01-02")])

result = values.get_indexer(target)
expected = np.array(positions, dtype=np.intp)
tm.assert_numpy_array_equal(result, expected)
Expand Down
36 changes: 36 additions & 0 deletions pandas/tests/scalar/timestamp/test_comparisons.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,42 @@ def test_compare_invalid(self):
assert val != np.float64(1)
assert val != np.int64(1)

@pytest.mark.parametrize("tz", [None, "US/Pacific"])
def test_compare_date(self, tz):
# GH#36131 comparing Timestamp with date object is deprecated
ts = Timestamp.now(tz)
dt = ts.to_pydatetime().date()
# These are incorrectly considered as equal because they
# dispatch to the date comparisons which truncates ts

for left, right in [(ts, dt), (dt, ts)]:
with tm.assert_produces_warning(FutureWarning):
assert left == right
with tm.assert_produces_warning(FutureWarning):
assert not left != right
with tm.assert_produces_warning(FutureWarning):
assert not left < right
with tm.assert_produces_warning(FutureWarning):
assert left <= right
with tm.assert_produces_warning(FutureWarning):
assert not left > right
with tm.assert_produces_warning(FutureWarning):
assert left >= right

# Once the deprecation is enforced, the following assertions
# can be enabled:
# assert not left == right
# assert left != right
#
# with pytest.raises(TypeError):
# left < right
# with pytest.raises(TypeError):
# left <= right
# with pytest.raises(TypeError):
# left > right
# with pytest.raises(TypeError):
# left >= right

def test_cant_compare_tz_naive_w_aware(self, utc_fixture):
# see GH#1404
a = Timestamp("3/12/2012")
Expand Down

0 comments on commit 965d58e

Please sign in to comment.