@@ -410,7 +410,7 @@ cdef class BaseOffset:
410
410
try :
411
411
# GH#23524 if to_offset fails, we are dealing with an
412
412
# incomparable type so == is False and != is True
413
- other = to_offset (other)
413
+ other = to_offset_eq (other)
414
414
except ValueError :
415
415
# e.g. "infer"
416
416
return False
@@ -990,7 +990,7 @@ cdef class Tick(SingleConstructorOffset):
990
990
try :
991
991
# GH#23524 if to_offset fails, we are dealing with an
992
992
# incomparable type so == is False and != is True
993
- other = to_offset (other)
993
+ other = to_offset_eq (other)
994
994
except ValueError :
995
995
# e.g. "infer"
996
996
return False
@@ -4157,7 +4157,7 @@ def _get_offset(name: str) -> BaseOffset:
4157
4157
return _offset_map[name]
4158
4158
4159
4159
4160
- cpdef to_offset(freq , is_period = None ):
4160
+ cpdef to_offset(freq , bint is_period ):
4161
4161
"""
4162
4162
Return DateOffset object from string or datetime.timedelta object.
4163
4163
@@ -4271,6 +4271,72 @@ cpdef to_offset(freq, is_period=None):
4271
4271
return delta
4272
4272
4273
4273
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
+
4274
4340
# ----------------------------------------------------------------------
4275
4341
# RelativeDelta Arithmetic
4276
4342
0 commit comments