@@ -1489,6 +1489,60 @@ cdef class PeriodMixin:
14891489 return FR_SEC
14901490 return base
14911491
1492+ @property
1493+ def start_time (self ) -> Timestamp:
1494+ """
1495+ Get the Timestamp for the start of the period.
1496+
1497+ Returns
1498+ -------
1499+ Timestamp
1500+
1501+ See Also
1502+ --------
1503+ Period.end_time : Return the end Timestamp.
1504+ Period.dayofyear : Return the day of year.
1505+ Period.daysinmonth : Return the days in that month.
1506+ Period.dayofweek : Return the day of the week.
1507+
1508+ Examples
1509+ --------
1510+ >>> period = pd.Period(' 2012-1-1' , freq = ' D' )
1511+ >>> period
1512+ Period('2012-01-01', 'D')
1513+
1514+ >>> period.start_time
1515+ Timestamp('2012-01-01 00:00:00')
1516+
1517+ >>> period.end_time
1518+ Timestamp('2012-01-01 23:59:59.999999999')
1519+ """
1520+ return self.to_timestamp(how = " start" )
1521+
1522+ @property
1523+ def end_time(self ) -> Timestamp:
1524+ return self.to_timestamp(how = " end" )
1525+
1526+ def _require_matching_freq(self , other , base = False ):
1527+ # See also arrays.period.raise_on_incompatible
1528+ if is_offset_object(other):
1529+ other_freq = other
1530+ else :
1531+ other_freq = other.freq
1532+
1533+ if base:
1534+ condition = self .freq.base != other_freq.base
1535+ else :
1536+ condition = self .freq != other_freq
1537+
1538+ if condition:
1539+ msg = DIFFERENT_FREQ.format(
1540+ cls = type (self ).__name__,
1541+ own_freq = self .freqstr,
1542+ other_freq = other_freq.freqstr,
1543+ )
1544+ raise IncompatibleFrequency(msg)
1545+
14921546
14931547cdef class _Period(PeriodMixin):
14941548
@@ -1551,10 +1605,7 @@ cdef class _Period(PeriodMixin):
15511605 return False
15521606 elif op == Py_NE:
15531607 return True
1554- msg = DIFFERENT_FREQ.format(cls = type (self ).__name__,
1555- own_freq = self .freqstr,
1556- other_freq = other.freqstr)
1557- raise IncompatibleFrequency(msg)
1608+ self ._require_matching_freq(other)
15581609 return PyObject_RichCompareBool(self .ordinal, other.ordinal, op)
15591610 elif other is NaT:
15601611 return _nat_scalar_rules[op]
@@ -1563,15 +1614,15 @@ cdef class _Period(PeriodMixin):
15631614 def __hash__ (self ):
15641615 return hash ((self .ordinal, self .freqstr))
15651616
1566- def _add_delta (self , other ) -> "Period":
1617+ def _add_timedeltalike_scalar (self , other ) -> "Period":
15671618 cdef:
1568- int64_t nanos , offset_nanos
1619+ int64_t nanos , base_nanos
15691620
15701621 if is_tick_object(self.freq ):
15711622 nanos = delta_to_nanoseconds(other)
1572- offset_nanos = self .freq.base.nanos
1573- if nanos % offset_nanos == 0 :
1574- ordinal = self .ordinal + (nanos // offset_nanos )
1623+ base_nanos = self .freq.base.nanos
1624+ if nanos % base_nanos == 0 :
1625+ ordinal = self .ordinal + (nanos // base_nanos )
15751626 return Period(ordinal = ordinal, freq = self .freq)
15761627 raise IncompatibleFrequency(" Input cannot be converted to "
15771628 f" Period(freq={self.freqstr})" )
@@ -1581,14 +1632,10 @@ cdef class _Period(PeriodMixin):
15811632 cdef:
15821633 int64_t ordinal
15831634
1584- if other.base == self.freq.base:
1585- ordinal = self .ordinal + other.n
1586- return Period(ordinal = ordinal, freq = self .freq)
1635+ self._require_matching_freq(other , base = True )
15871636
1588- msg = DIFFERENT_FREQ.format(cls = type (self ).__name__,
1589- own_freq = self .freqstr,
1590- other_freq = other.freqstr)
1591- raise IncompatibleFrequency(msg )
1637+ ordinal = self .ordinal + other.n
1638+ return Period(ordinal = ordinal, freq = self .freq)
15921639
15931640 def __add__(self , other ):
15941641 if not is_period_object(self ):
@@ -1598,7 +1645,7 @@ cdef class _Period(PeriodMixin):
15981645 return other.__add__ (self )
15991646
16001647 if is_any_td_scalar(other):
1601- return self ._add_delta (other)
1648+ return self ._add_timedeltalike_scalar (other)
16021649 elif is_offset_object(other):
16031650 return self ._add_offset(other)
16041651 elif other is NaT:
@@ -1635,11 +1682,7 @@ cdef class _Period(PeriodMixin):
16351682 ordinal = self .ordinal - other * self .freq.n
16361683 return Period(ordinal = ordinal, freq = self .freq)
16371684 elif is_period_object(other):
1638- if other.freq != self .freq:
1639- msg = DIFFERENT_FREQ.format(cls = type (self ).__name__,
1640- own_freq = self .freqstr,
1641- other_freq = other.freqstr)
1642- raise IncompatibleFrequency(msg)
1685+ self ._require_matching_freq(other)
16431686 # GH 23915 - mul by base freq since __add__ is agnostic of n
16441687 return (self .ordinal - other.ordinal) * self .freq.base
16451688 elif other is NaT:
@@ -1677,40 +1720,6 @@ cdef class _Period(PeriodMixin):
16771720
16781721 return Period(ordinal = ordinal, freq = freq)
16791722
1680- @property
1681- def start_time(self ) -> Timestamp:
1682- """
1683- Get the Timestamp for the start of the period.
1684-
1685- Returns
1686- -------
1687- Timestamp
1688-
1689- See Also
1690- --------
1691- Period.end_time : Return the end Timestamp.
1692- Period.dayofyear : Return the day of year.
1693- Period.daysinmonth : Return the days in that month.
1694- Period.dayofweek : Return the day of the week.
1695-
1696- Examples
1697- --------
1698- >>> period = pd.Period(' 2012-1-1' , freq = ' D' )
1699- >>> period
1700- Period('2012-01-01', 'D')
1701-
1702- >>> period.start_time
1703- Timestamp('2012-01-01 00:00:00')
1704-
1705- >>> period.end_time
1706- Timestamp('2012-01-01 23:59:59.999999999')
1707- """
1708- return self.to_timestamp(how = ' S' )
1709-
1710- @property
1711- def end_time(self ) -> Timestamp:
1712- return self.to_timestamp(how = " end" )
1713-
17141723 def to_timestamp(self , freq = None , how = ' start' , tz = None ) -> Timestamp:
17151724 """
17161725 Return the Timestamp representation of the Period.
0 commit comments