@@ -1580,36 +1580,37 @@ cdef class _Period:
1580
1580
return PyObject_RichCompareBool(self .ordinal, other.ordinal, op)
1581
1581
elif other is NaT:
1582
1582
return _nat_scalar_rules[op]
1583
- return NotImplemented
1583
+ return NotImplemented # TODO: ndarray[object]?
1584
1584
1585
1585
def __hash__ (self ):
1586
1586
return hash ((self .ordinal, self .freqstr))
1587
1587
1588
- def _add_delta (self , other ):
1588
+ def _add_delta (self , other ) -> "Period" :
1589
1589
cdef:
1590
1590
int64_t nanos , offset_nanos
1591
1591
1592
- if (PyDelta_Check(other) or util.is_timedelta64_object(other) or
1593
- is_tick_object(other)):
1594
- offset = to_offset(self .freq.rule_code)
1595
- if is_tick_object(offset):
1596
- nanos = delta_to_nanoseconds(other)
1597
- offset_nanos = delta_to_nanoseconds(offset)
1598
- if nanos % offset_nanos == 0 :
1599
- ordinal = self .ordinal + (nanos // offset_nanos)
1600
- return Period(ordinal = ordinal, freq = self .freq)
1601
- raise IncompatibleFrequency(" Input cannot be converted to "
1602
- f" Period(freq={self.freqstr})" )
1603
- elif is_offset_object(other):
1604
- if other.base == self .freq.base:
1605
- ordinal = self .ordinal + other.n
1592
+ if is_tick_object(self.freq ):
1593
+ nanos = delta_to_nanoseconds(other)
1594
+ offset_nanos = self .freq.base.nanos
1595
+ if nanos % offset_nanos == 0 :
1596
+ ordinal = self .ordinal + (nanos // offset_nanos)
1606
1597
return Period(ordinal = ordinal, freq = self .freq)
1607
- msg = DIFFERENT_FREQ.format(cls = type (self ).__name__,
1608
- own_freq = self .freqstr,
1609
- other_freq = other.freqstr)
1610
- raise IncompatibleFrequency(msg)
1611
- else : # pragma no cover
1612
- return NotImplemented
1598
+ raise IncompatibleFrequency(" Input cannot be converted to "
1599
+ f" Period(freq={self.freqstr})" )
1600
+
1601
+ def _add_offset (self , other ) -> "Period":
1602
+ # Non-Tick DateOffset other
1603
+ cdef:
1604
+ int64_t ordinal
1605
+
1606
+ if other.base == self.freq.base:
1607
+ ordinal = self .ordinal + other.n
1608
+ return Period(ordinal = ordinal, freq = self .freq)
1609
+
1610
+ msg = DIFFERENT_FREQ.format(cls = type (self ).__name__,
1611
+ own_freq = self .freqstr,
1612
+ other_freq = other.freqstr)
1613
+ raise IncompatibleFrequency(msg )
1613
1614
1614
1615
def __add__(self , other ):
1615
1616
if not is_period_object(self ):
@@ -1618,9 +1619,10 @@ cdef class _Period:
1618
1619
return NaT
1619
1620
return other.__add__ (self )
1620
1621
1621
- if (PyDelta_Check(other) or util.is_timedelta64_object(other) or
1622
- is_offset_object(other)):
1622
+ if is_any_tdlike_scalar(other):
1623
1623
return self ._add_delta(other)
1624
+ elif is_offset_object(other):
1625
+ return self ._add_offset(other)
1624
1626
elif other is NaT:
1625
1627
return NaT
1626
1628
elif util.is_integer_object(other):
@@ -1644,8 +1646,11 @@ cdef class _Period:
1644
1646
return NaT
1645
1647
return NotImplemented
1646
1648
1647
- elif (PyDelta_Check(other) or util.is_timedelta64_object(other) or
1648
- is_offset_object(other)):
1649
+ elif is_any_tdlike_scalar(other):
1650
+ neg_other = - other
1651
+ return self + neg_other
1652
+ elif is_offset_object(other):
1653
+ # Non-Tick DateOffset
1649
1654
neg_other = - other
1650
1655
return self + neg_other
1651
1656
elif util.is_integer_object(other):
@@ -2516,3 +2521,18 @@ def validate_end_alias(how):
2516
2521
if how not in {' S' , ' E' }:
2517
2522
raise ValueError (' How must be one of S or E' )
2518
2523
return how
2524
+
2525
+
2526
+ cpdef is_any_tdlike_scalar(object obj):
2527
+ """
2528
+ Cython equivalent for `isinstance(obj, (timedelta, np.timedelta64, Tick))`
2529
+
2530
+ Parameters
2531
+ ----------
2532
+ obj : object
2533
+
2534
+ Returns
2535
+ -------
2536
+ bool
2537
+ """
2538
+ return util.is_timedelta64_object(obj) or PyDelta_Check(obj) or is_tick_object(obj)
0 commit comments