Skip to content

Commit 129fbb0

Browse files
committed
FIX: date comparison fails when series is all pd.NaT values #61188
1 parent b69a2ae commit 129fbb0

File tree

3 files changed

+66
-0
lines changed

3 files changed

+66
-0
lines changed

doc/source/whatsnew/v3.0.0.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,7 @@ Datetimelike
660660
- Bug in :meth:`to_datetime` reports incorrect index in case of any failure scenario. (:issue:`58298`)
661661
- Bug in :meth:`to_datetime` wrongly converts when ``arg`` is a ``np.datetime64`` object with unit of ``ps``. (:issue:`60341`)
662662
- Bug in setting scalar values with mismatched resolution into arrays with non-nanosecond ``datetime64``, ``timedelta64`` or :class:`DatetimeTZDtype` incorrectly truncating those scalars (:issue:`56410`)
663+
- Bug in :attr:`Series.dt.date` where Series with all NaT values would raise an error when compared to a datetime.date (:issue:`61188`)
663664

664665
Timedelta
665666
^^^^^^^^^

pandas/core/indexes/accessors.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,53 @@ def freq(self):
396396
'2YS-JAN'
397397
"""
398398
return self._get_values().inferred_freq
399+
400+
@property
401+
def date(self):
402+
"""
403+
Return the date component (year, month, day) of each datetime in the Series.
404+
405+
This property returns a Series of Python datetime.date objects corresponding to
406+
the date portion of each datetime64[ns] value in the Series. For missing values
407+
(NaT), the result will be NaT.
408+
409+
Returns
410+
-------
411+
Series
412+
A Series of datetime.date objects or NaT, with dtype object.
413+
414+
Notes
415+
-----
416+
- The result is always returned with object dtype.
417+
- This ensures comparisons with Python datetime.date values (e.g. using <=)
418+
work even when the Series contains only missing values (NaT).
419+
420+
Examples
421+
--------
422+
>>> s = pd.Series(pd.to_datetime(["2020-01-01", pd.NaT]))
423+
>>> s.dt.date
424+
0 2020-01-01
425+
1 NaT
426+
dtype: object
427+
428+
>>> s.dt.date <= datetime.date(2024, 1, 1)
429+
0 True
430+
1 False
431+
dtype: bool
432+
"""
433+
434+
from pandas import Series
435+
import datetime
436+
437+
values = self._get_values()
438+
as_dates = values.to_pydatetime()
439+
440+
def extract_date(x):
441+
return x.date() if isinstance(x, datetime.datetime) else pd.NaT
442+
443+
result = [extract_date(v) for v in as_dates]
444+
445+
return Series(result, index=self._parent.index, name=self._parent.name, dtype=object).__finalize__(self._parent)
399446

400447
def isocalendar(self) -> DataFrame:
401448
"""

pandas/tests/series/indexing/test_datetime.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,3 +491,21 @@ def test_compare_datetime_with_all_none():
491491
result = ser > ser2
492492
expected = Series([False, False])
493493
tm.assert_series_equal(result, expected)
494+
495+
def test_dt_date_dtype_all_nat_is_object():
496+
# Ensure .dt.date on all-NaT Series returns object dtype and not datetime64
497+
# GH#61188
498+
s = pd.Series([pd.NaT, pd.NaT])
499+
s = pd.to_datetime(s)
500+
result = s.dt.date
501+
assert result.dtype == object
502+
assert result.isna().all()
503+
504+
def test_dt_date_all_nat_le_date():
505+
#All-NaT Series should not raise error when compared to a datetime.date
506+
# GH#61188
507+
s = pd.Series([pd.NaT, pd.NaT])
508+
s = pd.to_datetime(s)
509+
result = s.dt.date <= datetime.now().date()
510+
expected = pd.Series([False, False])
511+
tm.assert_series_equal(result, expected)

0 commit comments

Comments
 (0)