Skip to content

Commit b07c569

Browse files
committed
add to to_offset a boolean argument is_period IV [skip ci]
1 parent 9013d62 commit b07c569

File tree

4 files changed

+76
-10
lines changed

4 files changed

+76
-10
lines changed

Diff for: pandas/_libs/tslibs/offsets.pxd

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from numpy cimport int64_t
22

33

4-
cpdef to_offset(object obj)
4+
cpdef to_offset(object obj, bint is_period)
55
cdef bint is_offset_object(object obj)
66
cdef bint is_tick_object(object obj)
77

Diff for: pandas/_libs/tslibs/offsets.pyx

+69-3
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,7 @@ cdef class BaseOffset:
410410
try:
411411
# GH#23524 if to_offset fails, we are dealing with an
412412
# incomparable type so == is False and != is True
413-
other = to_offset(other)
413+
other = to_offset_eq(other)
414414
except ValueError:
415415
# e.g. "infer"
416416
return False
@@ -990,7 +990,7 @@ cdef class Tick(SingleConstructorOffset):
990990
try:
991991
# GH#23524 if to_offset fails, we are dealing with an
992992
# incomparable type so == is False and != is True
993-
other = to_offset(other)
993+
other = to_offset_eq(other)
994994
except ValueError:
995995
# e.g. "infer"
996996
return False
@@ -4157,7 +4157,7 @@ def _get_offset(name: str) -> BaseOffset:
41574157
return _offset_map[name]
41584158

41594159

4160-
cpdef to_offset(freq, is_period=None):
4160+
cpdef to_offset(freq, bint is_period):
41614161
"""
41624162
Return DateOffset object from string or datetime.timedelta object.
41634163
@@ -4271,6 +4271,72 @@ cpdef to_offset(freq, is_period=None):
42714271
return delta
42724272

42734273

4274+
cpdef to_offset_eq(freq):
4275+
if freq is None:
4276+
return None
4277+
4278+
if isinstance(freq, BaseOffset):
4279+
return freq
4280+
4281+
if isinstance(freq, tuple):
4282+
raise TypeError(
4283+
f"to_offset does not support tuples {freq}, pass as a string instead"
4284+
)
4285+
4286+
elif PyDelta_Check(freq):
4287+
return delta_to_tick(freq)
4288+
4289+
elif isinstance(freq, str):
4290+
delta = None
4291+
stride_sign = None
4292+
4293+
try:
4294+
split = opattern.split(freq)
4295+
if split[-1] != "" and not split[-1].isspace():
4296+
# the last element must be blank
4297+
raise ValueError("last element must be blank")
4298+
4299+
tups = zip(split[0::4], split[1::4], split[2::4])
4300+
for n, (sep, stride, name) in enumerate(tups):
4301+
if sep != "" and not sep.isspace():
4302+
raise ValueError("separator must be spaces")
4303+
prefix = _lite_rule_alias.get(name) or name
4304+
if stride_sign is None:
4305+
stride_sign = -1 if stride.startswith("-") else 1
4306+
if not stride:
4307+
stride = 1
4308+
4309+
if prefix in {"D", "H", "T", "S", "L", "U", "N"}:
4310+
# For these prefixes, we have something like "3H" or
4311+
# "2.5T", so we can construct a Timedelta with the
4312+
# matching unit and get our offset from delta_to_tick
4313+
td = Timedelta(1, unit=prefix)
4314+
off = delta_to_tick(td)
4315+
offset = off * float(stride)
4316+
if n != 0:
4317+
# If n==0, then stride_sign is already incorporated
4318+
# into the offset
4319+
offset *= stride_sign
4320+
else:
4321+
stride = int(stride)
4322+
offset = _get_offset(name)
4323+
offset = offset * int(np.fabs(stride) * stride_sign)
4324+
4325+
if delta is None:
4326+
delta = offset
4327+
else:
4328+
delta = delta + offset
4329+
except (ValueError, TypeError) as err:
4330+
raise ValueError(INVALID_FREQ_ERR_MSG.format(freq)) from err
4331+
else:
4332+
delta = None
4333+
4334+
if delta is None:
4335+
raise ValueError(INVALID_FREQ_ERR_MSG.format(freq))
4336+
4337+
return delta
4338+
4339+
42744340
# ----------------------------------------------------------------------
42754341
# RelativeDelta Arithmetic
42764342

Diff for: pandas/_libs/tslibs/period.pyx

+4-4
Original file line numberDiff line numberDiff line change
@@ -1470,7 +1470,7 @@ def from_ordinals(const int64_t[:] values, freq):
14701470
int64_t[::1] result = np.empty(len(values), dtype="i8")
14711471
int64_t val
14721472

1473-
freq = to_offset(freq)
1473+
freq = to_offset(freq, True)
14741474
if not isinstance(freq, BaseOffset):
14751475
raise ValueError("freq not specified and cannot be inferred")
14761476

@@ -1689,7 +1689,7 @@ cdef class _Period(PeriodMixin):
16891689
dtype = PeriodDtypeBase(freq)
16901690
freq = dtype._freqstr
16911691

1692-
freq = to_offset(freq)
1692+
freq = to_offset(freq, True)
16931693

16941694
if freq.n <= 0:
16951695
raise ValueError("Frequency must be positive, because it "
@@ -2672,7 +2672,7 @@ class Period(_Period):
26722672
if freq is None and ordinal != NPY_NAT:
26732673
# Skip NaT, since it doesn't have a resolution
26742674
freq = attrname_to_abbrevs[reso]
2675-
freq = to_offset(freq)
2675+
freq = to_offset(freq, True)
26762676

26772677
elif PyDateTime_Check(value):
26782678
dt = value
@@ -2753,7 +2753,7 @@ cdef _parse_weekly_str(value, BaseOffset freq):
27532753
if freq is None:
27542754
day_name = end.day_name()[:3].upper()
27552755
freqstr = f"W-{day_name}"
2756-
freq = to_offset(freqstr)
2756+
freq = to_offset(freqstr, True)
27572757
# We _should_ have freq.is_on_offset(end)
27582758

27592759
return end, freq

Diff for: pandas/_libs/tslibs/timestamps.pyx

+2-2
Original file line numberDiff line numberDiff line change
@@ -1671,11 +1671,11 @@ class Timestamp(_Timestamp):
16711671

16721672
return create_timestamp_from_ts(ts.value, ts.dts, ts.tzinfo, ts.fold, ts.creso)
16731673

1674-
def _round(self, freq, mode, ambiguous="raise", nonexistent="raise"):
1674+
def _round(self, freq, is_period, mode, ambiguous="raise", nonexistent="raise"):
16751675
cdef:
16761676
int64_t nanos
16771677

1678-
freq = to_offset(freq)
1678+
freq = to_offset(freq, is_period)
16791679
freq.nanos # raises on non-fixed freq
16801680
nanos = delta_to_nanoseconds(freq, self._creso)
16811681
if nanos == 0:

0 commit comments

Comments
 (0)