27
27
apply_index_wraps ,
28
28
roll_yearday ,
29
29
shift_month ,
30
- BeginMixin , EndMixin ,
30
+ EndMixin ,
31
31
BaseOffset )
32
32
33
33
@@ -1028,10 +1028,7 @@ def cbday(self):
1028
1028
1029
1029
@cache_readonly
1030
1030
def m_offset (self ):
1031
- kwds = self .kwds
1032
- kwds = {key : kwds [key ] for key in kwds
1033
- if key not in ['calendar' , 'weekmask' , 'holidays' , 'offset' ]}
1034
- return MonthEnd (n = 1 , normalize = self .normalize , ** kwds )
1031
+ return MonthEnd (n = 1 , normalize = self .normalize )
1035
1032
1036
1033
@apply_wraps
1037
1034
def apply (self , other ):
@@ -1106,10 +1103,7 @@ def cbday(self):
1106
1103
1107
1104
@cache_readonly
1108
1105
def m_offset (self ):
1109
- kwds = self .kwds
1110
- kwds = {key : kwds [key ] for key in kwds
1111
- if key not in ['calendar' , 'weekmask' , 'holidays' , 'offset' ]}
1112
- return MonthBegin (n = 1 , normalize = self .normalize , ** kwds )
1106
+ return MonthBegin (n = 1 , normalize = self .normalize )
1113
1107
1114
1108
@apply_wraps
1115
1109
def apply (self , other ):
@@ -1254,12 +1248,9 @@ def onOffset(self, dt):
1254
1248
1255
1249
def _apply (self , n , other ):
1256
1250
# if other.day is not day_of_month move to day_of_month and update n
1257
- if other .day < self .day_of_month :
1258
- other = other .replace (day = self .day_of_month )
1259
- if n > 0 :
1260
- n -= 1
1251
+ if n > 0 and other .day < self .day_of_month :
1252
+ n -= 1
1261
1253
elif other .day > self .day_of_month :
1262
- other = other .replace (day = self .day_of_month )
1263
1254
n += 1
1264
1255
1265
1256
months = n // 2
@@ -1309,12 +1300,9 @@ def onOffset(self, dt):
1309
1300
def _apply (self , n , other ):
1310
1301
# if other.day is not day_of_month move to day_of_month and update n
1311
1302
if other .day < self .day_of_month :
1312
- other = other .replace (day = self .day_of_month )
1313
1303
n -= 1
1314
- elif other .day > self .day_of_month :
1315
- other = other .replace (day = self .day_of_month )
1316
- if n <= 0 :
1317
- n += 1
1304
+ elif n <= 0 and other .day > self .day_of_month :
1305
+ n += 1
1318
1306
1319
1307
months = n // 2 + n % 2
1320
1308
day = 1 if n % 2 else self .day_of_month
@@ -1471,6 +1459,7 @@ def apply(self, other):
1471
1459
def getOffsetOfMonth (self , dt ):
1472
1460
w = Week (weekday = self .weekday )
1473
1461
d = datetime (dt .year , dt .month , 1 , tzinfo = dt .tzinfo )
1462
+ # TODO: Is this DST-safe?
1474
1463
d = w .rollforward (d )
1475
1464
return d + timedelta (weeks = self .week )
1476
1465
@@ -1550,6 +1539,7 @@ def getOffsetOfMonth(self, dt):
1550
1539
d = datetime (dt .year , dt .month , 1 , dt .hour , dt .minute ,
1551
1540
dt .second , dt .microsecond , tzinfo = dt .tzinfo )
1552
1541
eom = m .rollforward (d )
1542
+ # TODO: Is this DST-safe?
1553
1543
w = Week (weekday = self .weekday )
1554
1544
return w .rollback (eom )
1555
1545
@@ -1635,6 +1625,12 @@ def onOffset(self, dt):
1635
1625
modMonth = (dt .month - self .startingMonth ) % 3
1636
1626
return modMonth == 0 and dt .day == self ._get_offset_day (dt )
1637
1627
1628
+ @apply_index_wraps
1629
+ def apply_index (self , dtindex ):
1630
+ shifted = liboffsets .shift_quarters (dtindex .asi8 , self .n ,
1631
+ self .startingMonth , self ._day_opt )
1632
+ return dtindex ._shallow_copy (shifted )
1633
+
1638
1634
1639
1635
class BQuarterEnd (QuarterOffset ):
1640
1636
"""DateOffset increments between business Quarter dates
@@ -1659,7 +1655,7 @@ class BQuarterBegin(QuarterOffset):
1659
1655
_day_opt = 'business_start'
1660
1656
1661
1657
1662
- class QuarterEnd (EndMixin , QuarterOffset ):
1658
+ class QuarterEnd (QuarterOffset ):
1663
1659
"""DateOffset increments between business Quarter dates
1664
1660
startingMonth = 1 corresponds to dates like 1/31/2007, 4/30/2007, ...
1665
1661
startingMonth = 2 corresponds to dates like 2/28/2007, 5/31/2007, ...
@@ -1670,25 +1666,14 @@ class QuarterEnd(EndMixin, QuarterOffset):
1670
1666
_prefix = 'Q'
1671
1667
_day_opt = 'end'
1672
1668
1673
- @apply_index_wraps
1674
- def apply_index (self , i ):
1675
- return self ._end_apply_index (i , self .freqstr )
1676
-
1677
1669
1678
- class QuarterBegin (BeginMixin , QuarterOffset ):
1670
+ class QuarterBegin (QuarterOffset ):
1679
1671
_outputName = 'QuarterBegin'
1680
1672
_default_startingMonth = 3
1681
1673
_from_name_startingMonth = 1
1682
1674
_prefix = 'QS'
1683
1675
_day_opt = 'start'
1684
1676
1685
- @apply_index_wraps
1686
- def apply_index (self , i ):
1687
- freq_month = 12 if self .startingMonth == 1 else self .startingMonth - 1
1688
- month = liboffsets ._int_to_month [freq_month ]
1689
- freqstr = 'Q-{month}' .format (month = month )
1690
- return self ._beg_apply_index (i , freqstr )
1691
-
1692
1677
1693
1678
# ---------------------------------------------------------------------
1694
1679
# Year-Based Offset Classes
@@ -1709,6 +1694,13 @@ def apply(self, other):
1709
1694
months = years * 12 + (self .month - other .month )
1710
1695
return shift_month (other , months , self ._day_opt )
1711
1696
1697
+ @apply_index_wraps
1698
+ def apply_index (self , dtindex ):
1699
+ shifted = liboffsets .shift_quarters (dtindex .asi8 , self .n ,
1700
+ self .month , self ._day_opt ,
1701
+ modby = 12 )
1702
+ return dtindex ._shallow_copy (shifted )
1703
+
1712
1704
def onOffset (self , dt ):
1713
1705
if self .normalize and not _is_normalized (dt ):
1714
1706
return False
@@ -1752,31 +1744,19 @@ class BYearBegin(YearOffset):
1752
1744
_day_opt = 'business_start'
1753
1745
1754
1746
1755
- class YearEnd (EndMixin , YearOffset ):
1747
+ class YearEnd (YearOffset ):
1756
1748
"""DateOffset increments between calendar year ends"""
1757
1749
_default_month = 12
1758
1750
_prefix = 'A'
1759
1751
_day_opt = 'end'
1760
1752
1761
- @apply_index_wraps
1762
- def apply_index (self , i ):
1763
- # convert month anchor to annual period tuple
1764
- return self ._end_apply_index (i , self .freqstr )
1765
1753
1766
-
1767
- class YearBegin (BeginMixin , YearOffset ):
1754
+ class YearBegin (YearOffset ):
1768
1755
"""DateOffset increments between calendar year begin dates"""
1769
1756
_default_month = 1
1770
1757
_prefix = 'AS'
1771
1758
_day_opt = 'start'
1772
1759
1773
- @apply_index_wraps
1774
- def apply_index (self , i ):
1775
- freq_month = 12 if self .month == 1 else self .month - 1
1776
- month = liboffsets ._int_to_month [freq_month ]
1777
- freqstr = 'A-{month}' .format (month = month )
1778
- return self ._beg_apply_index (i , freqstr )
1779
-
1780
1760
1781
1761
# ---------------------------------------------------------------------
1782
1762
# Special Offset Classes
@@ -2245,7 +2225,8 @@ def __eq__(self, other):
2245
2225
if isinstance (other , Tick ):
2246
2226
return self .delta == other .delta
2247
2227
else :
2248
- return DateOffset .__eq__ (self , other )
2228
+ # TODO: Are there cases where this should raise TypeError?
2229
+ return False
2249
2230
2250
2231
# This is identical to DateOffset.__hash__, but has to be redefined here
2251
2232
# for Python 3, because we've redefined __eq__.
@@ -2261,7 +2242,8 @@ def __ne__(self, other):
2261
2242
if isinstance (other , Tick ):
2262
2243
return self .delta != other .delta
2263
2244
else :
2264
- return DateOffset .__ne__ (self , other )
2245
+ # TODO: Are there cases where this should raise TypeError?
2246
+ return True
2265
2247
2266
2248
@property
2267
2249
def delta (self ):
0 commit comments