Skip to content

Commit 3198f2f

Browse files
committed
Merge branch 'main' into daydst2
2 parents 3644e75 + b5b8be0 commit 3198f2f

File tree

7 files changed

+31
-38
lines changed

7 files changed

+31
-38
lines changed

pandas/_libs/tslibs/timedeltas.pxd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ from numpy cimport int64_t
44
from .np_datetime cimport NPY_DATETIMEUNIT
55

66

7+
cpdef int64_t get_unit_for_round(freq, NPY_DATETIMEUNIT creso) except? -1
78
# Exposed for tslib, not intended for outside use.
89
cpdef int64_t delta_to_nanoseconds(
910
delta, NPY_DATETIMEUNIT reso=*, bint round_ok=*

pandas/_libs/tslibs/timedeltas.pyi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ UnitChoices: TypeAlias = Literal[
6868
]
6969
_S = TypeVar("_S", bound=timedelta)
7070

71+
def get_unit_for_round(freq, creso: int) -> int: ...
72+
def disallow_ambiguous_unit(unit: str | None) -> None: ...
7173
def ints_to_pytimedelta(
7274
arr: npt.NDArray[np.timedelta64],
7375
box: bool = ...,

pandas/_libs/tslibs/timedeltas.pyx

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -827,6 +827,14 @@ def _binary_op_method_timedeltalike(op, name):
827827
# ----------------------------------------------------------------------
828828
# Timedelta Construction
829829

830+
cpdef disallow_ambiguous_unit(unit):
831+
if unit in {"Y", "y", "M"}:
832+
raise ValueError(
833+
"Units 'M', 'Y', and 'y' are no longer supported, as they do not "
834+
"represent unambiguous timedelta values durations."
835+
)
836+
837+
830838
cdef int64_t parse_iso_format_string(str ts) except? -1:
831839
"""
832840
Extracts and cleanses the appropriate values from a match object with
@@ -1815,11 +1823,7 @@ class Timedelta(_Timedelta):
18151823
)
18161824
raise OutOfBoundsTimedelta(msg) from err
18171825

1818-
if unit in {"Y", "y", "M"}:
1819-
raise ValueError(
1820-
"Units 'M', 'Y', and 'y' are no longer supported, as they do not "
1821-
"represent unambiguous timedelta values durations."
1822-
)
1826+
disallow_ambiguous_unit(unit)
18231827

18241828
# GH 30543 if pd.Timedelta already passed, return it
18251829
# check that only value is passed
@@ -1932,13 +1936,7 @@ class Timedelta(_Timedelta):
19321936
int64_t result, unit
19331937
ndarray[int64_t] arr
19341938

1935-
from pandas._libs.tslibs.offsets import to_offset
1936-
1937-
orig = freq
1938-
# In this context it is sufficiently clear that "D" this means 24H
1939-
freq = to_offset(freq)._maybe_to_hours()
1940-
freq.nanos # raises on non-fixed freq
1941-
unit = delta_to_nanoseconds(to_offset(freq), self._creso)
1939+
unit = get_unit_for_round(freq, self._creso)
19421940

19431941
arr = np.array([self._value], dtype="i8")
19441942
try:
@@ -2295,3 +2293,12 @@ cdef bint _should_cast_to_timedelta(object obj):
22952293
return (
22962294
is_any_td_scalar(obj) or obj is None or obj is NaT or isinstance(obj, str)
22972295
)
2296+
2297+
2298+
cpdef int64_t get_unit_for_round(freq, NPY_DATETIMEUNIT creso) except? -1:
2299+
from pandas._libs.tslibs.offsets import to_offset
2300+
2301+
# In this context it is unambiguous that "D" represents 24 hours
2302+
freq = to_offset(freq)._maybe_to_hours()
2303+
freq.nanos # raises on non-fixed freq
2304+
return delta_to_nanoseconds(freq, creso)

pandas/_libs/tslibs/timestamps.pyx

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ from pandas._libs.tslibs.np_datetime import (
107107
from pandas._libs.tslibs.offsets cimport to_offset
108108
from pandas._libs.tslibs.timedeltas cimport (
109109
_Timedelta,
110-
delta_to_nanoseconds,
110+
get_unit_for_round,
111111
is_any_td_scalar,
112112
)
113113

@@ -1895,19 +1895,15 @@ class Timestamp(_Timestamp):
18951895
cdef:
18961896
int64_t nanos
18971897

1898-
# In this context it is sufficiently clear that "D" this means 24H
1899-
freq = to_offset(freq, is_period=False)._maybe_to_hours()
1900-
freq.nanos # raises on non-fixed freq
1901-
nanos = delta_to_nanoseconds(freq, self._creso)
1898+
freq = to_offset(freq, is_period=False)
1899+
nanos = get_unit_for_round(freq, self._creso)
19021900
if nanos == 0:
19031901
if freq.nanos == 0:
19041902
raise ValueError("Division by zero in rounding")
19051903

19061904
# e.g. self.unit == "s" and sub-second freq
19071905
return self
19081906

1909-
# TODO: problem if nanos==0
1910-
19111907
if self.tz is not None:
19121908
value = self.tz_localize(None)._value
19131909
else:

pandas/core/arrays/datetimelike.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
Timedelta,
3838
Timestamp,
3939
astype_overflowsafe,
40-
delta_to_nanoseconds,
4140
get_unit_from_dtype,
4241
iNaT,
4342
ints_to_pydatetime,
@@ -50,6 +49,7 @@
5049
round_nsint64,
5150
)
5251
from pandas._libs.tslibs.np_datetime import compare_mismatched_resolutions
52+
from pandas._libs.tslibs.timedeltas import get_unit_for_round
5353
from pandas._libs.tslibs.timestamps import integer_op_not_supported
5454
from pandas._typing import (
5555
ArrayLike,
@@ -2149,13 +2149,7 @@ def _round(self, freq, mode, ambiguous, nonexistent):
21492149

21502150
values = self.view("i8")
21512151
values = cast(np.ndarray, values)
2152-
offset = to_offset(freq)
2153-
2154-
# In this context it is clear "D" means "24H"
2155-
offset = offset._maybe_to_hours()
2156-
2157-
offset.nanos # raises on non-fixed frequencies
2158-
nanos = delta_to_nanoseconds(offset, self._creso)
2152+
nanos = get_unit_for_round(freq, self._creso)
21592153
if nanos == 0:
21602154
# GH 52761
21612155
return self.copy()

pandas/core/indexes/timedeltas.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
Timedelta,
1515
to_offset,
1616
)
17+
from pandas._libs.tslibs.timedeltas import disallow_ambiguous_unit
1718
from pandas.util._exceptions import find_stack_level
1819

1920
from pandas.core.dtypes.common import (
@@ -171,11 +172,7 @@ def __new__(
171172
if is_scalar(data):
172173
cls._raise_scalar_data_error(data)
173174

174-
if unit in {"Y", "y", "M"}:
175-
raise ValueError(
176-
"Units 'M', 'Y', and 'y' are no longer supported, as they do not "
177-
"represent unambiguous timedelta values durations."
178-
)
175+
disallow_ambiguous_unit(unit)
179176
if dtype is not None:
180177
dtype = pandas_dtype(dtype)
181178

pandas/core/tools/timedeltas.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
)
1818
from pandas._libs.tslibs.timedeltas import (
1919
Timedelta,
20+
disallow_ambiguous_unit,
2021
parse_timedelta_unit,
2122
)
2223

@@ -178,16 +179,11 @@ def to_timedelta(
178179
"""
179180
if unit is not None:
180181
unit = parse_timedelta_unit(unit)
182+
disallow_ambiguous_unit(unit)
181183

182184
if errors not in ("ignore", "raise", "coerce"):
183185
raise ValueError("errors must be one of 'ignore', 'raise', or 'coerce'.")
184186

185-
if unit in {"Y", "y", "M"}:
186-
raise ValueError(
187-
"Units 'M', 'Y', and 'y' are no longer supported, as they do not "
188-
"represent unambiguous timedelta values durations."
189-
)
190-
191187
if arg is None:
192188
return arg
193189
elif isinstance(arg, ABCSeries):

0 commit comments

Comments
 (0)