Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/source/whatsnew/v3.0.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,7 @@ Datetimelike
- Bug in :meth:`to_datetime` reports incorrect index in case of any failure scenario. (:issue:`58298`)
- Bug in :meth:`to_datetime` wrongly converts when ``arg`` is a ``np.datetime64`` object with unit of ``ps``. (:issue:`60341`)
- Bug in setting scalar values with mismatched resolution into arrays with non-nanosecond ``datetime64``, ``timedelta64`` or :class:`DatetimeTZDtype` incorrectly truncating those scalars (:issue:`56410`)
- Bug in :attr:`Series.dt.date` where Series with all NaT values would raise an error when compared to a datetime.date (:issue:`61188`)

Timedelta
^^^^^^^^^
Expand Down
47 changes: 47 additions & 0 deletions pandas/core/indexes/accessors.py
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,53 @@ def freq(self):
'2YS-JAN'
"""
return self._get_values().inferred_freq

@property
def date(self):
"""
Return the date component (year, month, day) of each datetime in the Series.

This property returns a Series of Python datetime.date objects corresponding to
the date portion of each datetime64[ns] value in the Series. For missing values
(NaT), the result will be NaT.

Returns
-------
Series
A Series of datetime.date objects or NaT, with dtype object.

Notes
-----
- The result is always returned with object dtype.
- This ensures comparisons with Python datetime.date values (e.g. using <=)
work even when the Series contains only missing values (NaT).

Examples
--------
>>> s = pd.Series(pd.to_datetime(["2020-01-01", pd.NaT]))
>>> s.dt.date
0 2020-01-01
1 NaT
dtype: object

>>> s.dt.date <= datetime.date(2024, 1, 1)
0 True
1 False
dtype: bool
"""

from pandas import Series
import datetime

values = self._get_values()
as_dates = values.to_pydatetime()

def extract_date(x):
return x.date() if isinstance(x, datetime.datetime) else pd.NaT

result = [extract_date(v) for v in as_dates]

return Series(result, index=self._parent.index, name=self._parent.name, dtype=object).__finalize__(self._parent)

def isocalendar(self) -> DataFrame:
"""
Expand Down
18 changes: 18 additions & 0 deletions pandas/tests/series/indexing/test_datetime.py
Original file line number Diff line number Diff line change
Expand Up @@ -491,3 +491,21 @@ def test_compare_datetime_with_all_none():
result = ser > ser2
expected = Series([False, False])
tm.assert_series_equal(result, expected)

def test_dt_date_dtype_all_nat_is_object():
# Ensure .dt.date on all-NaT Series returns object dtype and not datetime64
# GH#61188
s = pd.Series([pd.NaT, pd.NaT])
s = pd.to_datetime(s)
result = s.dt.date
assert result.dtype == object
assert result.isna().all()

def test_dt_date_all_nat_le_date():
#All-NaT Series should not raise error when compared to a datetime.date
# GH#61188
s = pd.Series([pd.NaT, pd.NaT])
s = pd.to_datetime(s)
result = s.dt.date <= datetime.now().date()
expected = pd.Series([False, False])
tm.assert_series_equal(result, expected)
Loading