Skip to content
Merged
Changes from 15 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
3ce2133
REF: Replace @Substitution with hardcoded docstring in strftime
Nov 11, 2025
7eb63bd
REF: Replace @Substitution with hardcoded docstring in strftime
Nov 11, 2025
439358d
Merge branch 'main' into remove-doc-decorators
Chiwendaiyue Nov 11, 2025
372e8fe
chang int the correct url
Nov 11, 2025
bacb59e
Merge branch 'remove-doc-decorators' of github.com:Chiwendaiyue/panda…
Nov 11, 2025
0532ca4
Merge branch 'main' into remove-doc-decorators
Chiwendaiyue Nov 12, 2025
6fcd50d
remove %%
Nov 12, 2025
ca77c75
Merge branch 'main' into remove-doc-decorators
Chiwendaiyue Nov 13, 2025
b00b046
Merge branch 'main' into remove-doc-decorators
Chiwendaiyue Nov 14, 2025
9dba668
Merge branch 'main' into remove-doc-decorators
Chiwendaiyue Nov 15, 2025
d12a477
Merge branch 'main' into remove-doc-decorators
Chiwendaiyue Nov 26, 2025
26bade0
fix run doctests
Nov 26, 2025
8592782
Merge branch 'remove-doc-decorators' of github.com:Chiwendaiyue/panda…
Nov 26, 2025
fd5cf91
Merge branch 'main' into remove-doc-decorators
Chiwendaiyue Nov 26, 2025
76cb3ce
fix precision
Nov 26, 2025
820a80a
Merge branch 'main' into remove-doc-decorators
Chiwendaiyue Nov 27, 2025
a113e3e
Remove extra documents
Nov 27, 2025
ad81150
Merge branch 'remove-doc-decorators' of github.com:Chiwendaiyue/panda…
Nov 27, 2025
08b2c46
Merge branch 'main' into remove-doc-decorators
Chiwendaiyue Nov 29, 2025
cbcad50
Fix the accuracy
Nov 29, 2025
47efce7
Merge branch 'remove-doc-decorators' of github.com:Chiwendaiyue/panda…
Nov 29, 2025
7a1690c
Fix the accuracy for specific problem
Nov 29, 2025
e06b048
Merge branch 'main' into remove-doc-decorators
Chiwendaiyue Nov 29, 2025
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
308 changes: 294 additions & 14 deletions pandas/core/arrays/datetimelike.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,6 @@
PerformanceWarning,
)
from pandas.util._decorators import (
Appender,
Substitution,
cache_readonly,
)
from pandas.util._exceptions import find_stack_level
Expand Down Expand Up @@ -1779,23 +1777,20 @@ class DatelikeOps(DatetimeLikeArrayMixin):
Common ops for DatetimeIndex/PeriodIndex, but not TimedeltaIndex.
"""

@Substitution(
URL="https://docs.python.org/3/library/datetime.html"
"#strftime-and-strptime-behavior"
)
def strftime(self, date_format: str) -> npt.NDArray[np.object_]:
"""
Convert to Index using specified date_format.

Return an Index of formatted strings specified by date_format, which
supports the same string format as the python standard library. Details
of the string format can be found in `python string format
doc <%(URL)s>`__.
doc <https://docs.python.org/3/library/datetime.html
#strftime-and-strptime-behavior>`__.

Formats supported by the C `strftime` API but not by the python string format
doc (such as `"%%R"`, `"%%r"`) are not officially supported and should be
preferably replaced with their supported equivalents (such as `"%%H:%%M"`,
`"%%I:%%M:%%S %%p"`).
doc (such as `"%R"`, `"%r"`) are not officially supported and should be
preferably replaced with their supported equivalents (such as `"%H:%M"`,
`"%I:%M:%S %p"`).

Note that `PeriodIndex` support additional directives, detailed in
`Period.strftime`.
Expand All @@ -1822,7 +1817,7 @@ def strftime(self, date_format: str) -> npt.NDArray[np.object_]:
Examples
--------
>>> rng = pd.date_range(pd.Timestamp("2018-03-10 09:00"), periods=3, freq="s")
>>> rng.strftime("%%B %%d, %%Y, %%r")
>>> rng.strftime("%B %d, %Y, %r")
Index(['March 10, 2018, 09:00:00 AM', 'March 10, 2018, 09:00:01 AM',
'March 10, 2018, 09:00:02 AM'],
dtype='str')
Expand Down Expand Up @@ -2263,31 +2258,316 @@ def _round(self, freq, mode, ambiguous, nonexistent):
result = result.view(self._ndarray.dtype)
return self._simple_new(result, dtype=self.dtype)

@Appender((_round_doc + _round_example).format(op="round"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you remove _round_doc, _round_example, _floor_example, and _ceil_example?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already done, thanks for your review!

def round(
self,
freq,
ambiguous: TimeAmbiguous = "raise",
nonexistent: TimeNonexistent = "raise",
) -> Self:
"""
Perform round operation on the data to the specified `freq`.

Parameters
----------
freq : str or Offset
The frequency level to round the index to. Must be a fixed
frequency like 's' (second) not 'ME' (month end). See
:ref:`frequency aliases <timeseries.offset_aliases>` for
a list of possible `freq` values.
ambiguous : 'infer', bool-ndarray, 'NaT', default 'raise'
Only relevant for DatetimeIndex:

- 'infer' will attempt to infer fall dst-transition hours based on
order
- bool-ndarray where True signifies a DST time, False designates
a non-DST time (note that this flag is only applicable for
ambiguous times)
- 'NaT' will return NaT where there are ambiguous times
- 'raise' will raise a ValueError if there are ambiguous
times.

nonexistent : 'shift_forward', 'shift_backward', 'NaT', timedelta, \
default 'raise'
A nonexistent time does not exist in a particular timezone
where clocks moved forward due to DST.

- 'shift_forward' will shift the nonexistent time forward to the
closest existing time
- 'shift_backward' will shift the nonexistent time backward to the
closest existing time
- 'NaT' will return NaT where there are nonexistent times
- timedelta objects will shift nonexistent times by the timedelta
- 'raise' will raise a ValueError if there are
nonexistent times.

Returns
-------
DatetimeIndex, TimedeltaIndex, or Series
Index of the same type for a DatetimeIndex or TimedeltaIndex,
or a Series with the same index for a Series.

Raises
------
ValueError if the `freq` cannot be converted.

See Also
--------
DatetimeIndex.floor :
Perform floor operation on the data to the specified `freq`.
DatetimeIndex.snap :
Snap time stamps to nearest occurring frequency.

Notes
-----
If the timestamps have a timezone, rounding will take place relative to the
local ("wall") time and re-localized to the same timezone. When rounding
near daylight savings time, use ``nonexistent`` and ``ambiguous`` to
control the re-localization behavior.

Examples
--------
**DatetimeIndex**

>>> rng = pd.date_range("1/1/2018 11:59:00", periods=3, freq="min")
>>> rng
DatetimeIndex(['2018-01-01 11:59:00', '2018-01-01 12:00:00',
'2018-01-01 12:01:00'],
dtype='datetime64[ns]', freq='min')

>>> rng.round('h')
DatetimeIndex(['2018-01-01 12:00:00', '2018-01-01 12:00:00',
'2018-01-01 12:00:00'],
dtype='datetime64[ns]', freq=None)

**Series**

>>> pd.Series(rng).dt.round("h")
0 2018-01-01 12:00:00
1 2018-01-01 12:00:00
2 2018-01-01 12:00:00
dtype: datetime64[ns]

When rounding near a daylight savings time transition, use ``ambiguous`` or
``nonexistent`` to control how the timestamp should be re-localized.

>>> rng_tz = pd.DatetimeIndex(["2021-10-31 03:30:00"], tz="Europe/Amsterdam")

>>> rng_tz.floor("2h", ambiguous=False)
DatetimeIndex(['2021-10-31 02:00:00+01:00'],
dtype='datetime64[us, Europe/Amsterdam]', freq=None)

>>> rng_tz.floor("2h", ambiguous=True)
DatetimeIndex(['2021-10-31 02:00:00+02:00'],
dtype='datetime64[us, Europe/Amsterdam]', freq=None)
"""
return self._round(freq, RoundTo.NEAREST_HALF_EVEN, ambiguous, nonexistent)

@Appender((_round_doc + _floor_example).format(op="floor"))
def floor(
self,
freq,
ambiguous: TimeAmbiguous = "raise",
nonexistent: TimeNonexistent = "raise",
) -> Self:
"""
Perform floor operation on the data to the specified `freq`.

Parameters
----------
freq : str or Offset
The frequency level to floor the index to. Must be a fixed
frequency like 's' (second) not 'ME' (month end). See
:ref:`frequency aliases <timeseries.offset_aliases>` for
a list of possible `freq` values.
ambiguous : 'infer', bool-ndarray, 'NaT', default 'raise'
Only relevant for DatetimeIndex:

- 'infer' will attempt to infer fall dst-transition hours based on
order
- bool-ndarray where True signifies a DST time, False designates
a non-DST time (note that this flag is only applicable for
ambiguous times)
- 'NaT' will return NaT where there are ambiguous times
- 'raise' will raise a ValueError if there are ambiguous
times.

nonexistent : 'shift_forward', 'shift_backward', 'NaT', timedelta, \
default 'raise'
A nonexistent time does not exist in a particular timezone
where clocks moved forward due to DST.

- 'shift_forward' will shift the nonexistent time forward to the
closest existing time
- 'shift_backward' will shift the nonexistent time backward to the
closest existing time
- 'NaT' will return NaT where there are nonexistent times
- timedelta objects will shift nonexistent times by the timedelta
- 'raise' will raise a ValueError if there are
nonexistent times.

Returns
-------
DatetimeIndex, TimedeltaIndex, or Series
Index of the same type for a DatetimeIndex or TimedeltaIndex,
or a Series with the same index for a Series.

Raises
------
ValueError if the `freq` cannot be converted.

See Also
--------
DatetimeIndex.floor :
Perform floor operation on the data to the specified `freq`.
DatetimeIndex.snap :
Snap time stamps to nearest occurring frequency.

Notes
-----
If the timestamps have a timezone, flooring will take place relative to the
local ("wall") time and re-localized to the same timezone. When flooring
near daylight savings time, use ``nonexistent`` and ``ambiguous`` to
control the re-localization behavior.

Examples
--------
**DatetimeIndex**

>>> rng = pd.date_range("1/1/2018 11:59:00", periods=3, freq="min")
>>> rng
DatetimeIndex(['2018-01-01 11:59:00', '2018-01-01 12:00:00',
'2018-01-01 12:01:00'],
dtype='datetime64[ns]', freq='min')

>>> rng.floor('h')
DatetimeIndex(['2018-01-01 11:00:00', '2018-01-01 12:00:00',
'2018-01-01 12:00:00'],
dtype='datetime64[ns]', freq=None)

**Series**

>>> pd.Series(rng).dt.floor("h")
0 2018-01-01 11:00:00
1 2018-01-01 12:00:00
2 2018-01-01 12:00:00
dtype: datetime64[ns]

When rounding near a daylight savings time transition, use ``ambiguous`` or
``nonexistent`` to control how the timestamp should be re-localized.

>>> rng_tz = pd.DatetimeIndex(["2021-10-31 03:30:00"], tz="Europe/Amsterdam")

>>> rng_tz.floor("2h", ambiguous=False)
DatetimeIndex(['2021-10-31 02:00:00+01:00'],
dtype='datetime64[us, Europe/Amsterdam]', freq=None)

>>> rng_tz.floor("2h", ambiguous=True)
DatetimeIndex(['2021-10-31 02:00:00+02:00'],
dtype='datetime64[us, Europe/Amsterdam]', freq=None)
"""
return self._round(freq, RoundTo.MINUS_INFTY, ambiguous, nonexistent)

@Appender((_round_doc + _ceil_example).format(op="ceil"))
def ceil(
self,
freq,
ambiguous: TimeAmbiguous = "raise",
nonexistent: TimeNonexistent = "raise",
) -> Self:
"""
Perform ceil operation on the data to the specified `freq`.

Parameters
----------
freq : str or Offset
The frequency level to ceil the index to. Must be a fixed
frequency like 's' (second) not 'ME' (month end). See
:ref:`frequency aliases <timeseries.offset_aliases>` for
a list of possible `freq` values.
ambiguous : 'infer', bool-ndarray, 'NaT', default 'raise'
Only relevant for DatetimeIndex:

- 'infer' will attempt to infer fall dst-transition hours based on
order
- bool-ndarray where True signifies a DST time, False designates
a non-DST time (note that this flag is only applicable for
ambiguous times)
- 'NaT' will return NaT where there are ambiguous times
- 'raise' will raise a ValueError if there are ambiguous
times.

nonexistent : 'shift_forward', 'shift_backward', 'NaT', timedelta, \
default 'raise'
A nonexistent time does not exist in a particular timezone
where clocks moved forward due to DST.

- 'shift_forward' will shift the nonexistent time forward to the
closest existing time
- 'shift_backward' will shift the nonexistent time backward to the
closest existing time
- 'NaT' will return NaT where there are nonexistent times
- timedelta objects will shift nonexistent times by the timedelta
- 'raise' will raise a ValueError if there are
nonexistent times.

Returns
-------
DatetimeIndex, TimedeltaIndex, or Series
Index of the same type for a DatetimeIndex or TimedeltaIndex,
or a Series with the same index for a Series.

Raises
------
ValueError if the `freq` cannot be converted.

See Also
--------
DatetimeIndex.floor :
Perform floor operation on the data to the specified `freq`.
DatetimeIndex.snap :
Snap time stamps to nearest occurring frequency.

Notes
-----
If the timestamps have a timezone, ceiling will take place relative to the
local ("wall") time and re-localized to the same timezone. When ceiling
near daylight savings time, use ``nonexistent`` and ``ambiguous`` to
control the re-localization behavior.

Examples
--------
**DatetimeIndex**

>>> rng = pd.date_range("1/1/2018 11:59:00", periods=3, freq="min")
>>> rng
DatetimeIndex(['2018-01-01 11:59:00', '2018-01-01 12:00:00',
'2018-01-01 12:01:00'],
dtype='datetime64[ns]', freq='min')

>>> rng.ceil('h')
DatetimeIndex(['2018-01-01 12:00:00', '2018-01-01 12:00:00',
'2018-01-01 13:00:00'],
dtype='datetime64[ns]', freq=None)

**Series**

>>> pd.Series(rng).dt.ceil("h")
0 2018-01-01 12:00:00
1 2018-01-01 12:00:00
2 2018-01-01 13:00:00
dtype: datetime64[ns]

When rounding near a daylight savings time transition, use ``ambiguous`` or
``nonexistent`` to control how the timestamp should be re-localized.

>>> rng_tz = pd.DatetimeIndex(["2021-10-31 01:30:00"], tz="Europe/Amsterdam")

>>> rng_tz.ceil("h", ambiguous=False)
DatetimeIndex(['2021-10-31 02:00:00+01:00'],
dtype='datetime64[us, Europe/Amsterdam]', freq=None)

>>> rng_tz.ceil("h", ambiguous=True)
DatetimeIndex(['2021-10-31 02:00:00+02:00'],
dtype='datetime64[us, Europe/Amsterdam]', freq=None)
"""
return self._round(freq, RoundTo.PLUS_INFTY, ambiguous, nonexistent)

# --------------------------------------------------------------
Expand Down
Loading