@@ -1814,13 +1814,6 @@ def __init__(self, n=1, normalize=False, weekday=0, startingMonth=1,
1814
1814
raise ValueError ('{variation} is not a valid variation'
1815
1815
.format (variation = self .variation ))
1816
1816
1817
- @cache_readonly
1818
- def _offset_lwom (self ):
1819
- if self .variation == "nearest" :
1820
- return None
1821
- else :
1822
- return LastWeekOfMonth (n = 1 , weekday = self .weekday )
1823
-
1824
1817
def isAnchored (self ):
1825
1818
return (self .n == 1 and
1826
1819
self .startingMonth is not None and
@@ -1841,6 +1834,8 @@ def onOffset(self, dt):
1841
1834
1842
1835
@apply_wraps
1843
1836
def apply (self , other ):
1837
+ norm = Timestamp (other ).normalize ()
1838
+
1844
1839
n = self .n
1845
1840
prev_year = self .get_year_end (
1846
1841
datetime (other .year - 1 , self .startingMonth , 1 ))
@@ -1853,32 +1848,26 @@ def apply(self, other):
1853
1848
cur_year = tslib ._localize_pydatetime (cur_year , other .tzinfo )
1854
1849
next_year = tslib ._localize_pydatetime (next_year , other .tzinfo )
1855
1850
1856
- if other == prev_year :
1851
+ # Note: next_year.year == other.year + 1, so we will always
1852
+ # have other < next_year
1853
+ if norm == prev_year :
1857
1854
n -= 1
1858
- elif other == cur_year :
1855
+ elif norm == cur_year :
1859
1856
pass
1860
- elif other == next_year :
1861
- n += 1
1862
- # TODO: Not hit in tests
1863
1857
elif n > 0 :
1864
- if other < prev_year :
1858
+ if norm < prev_year :
1865
1859
n -= 2
1866
- elif prev_year < other < cur_year :
1860
+ elif prev_year < norm < cur_year :
1867
1861
n -= 1
1868
- elif cur_year < other < next_year :
1862
+ elif cur_year < norm < next_year :
1869
1863
pass
1870
- else :
1871
- assert False
1872
1864
else :
1873
- if next_year < other :
1874
- n += 2
1875
- # TODO: Not hit in tests; UPDATE: looks impossible
1876
- elif cur_year < other < next_year :
1865
+ if cur_year < norm < next_year :
1877
1866
n += 1
1878
- elif prev_year < other < cur_year :
1867
+ elif prev_year < norm < cur_year :
1879
1868
pass
1880
- elif (other .year == prev_year .year and other < prev_year and
1881
- prev_year - other <= timedelta (6 )):
1869
+ elif (norm .year == prev_year .year and norm < prev_year and
1870
+ prev_year - norm <= timedelta (6 )):
1882
1871
# GH#14774, error when next_year.year == cur_year.year
1883
1872
# e.g. prev_year == datetime(2004, 1, 3),
1884
1873
# other == datetime(2004, 1, 1)
@@ -1894,35 +1883,30 @@ def apply(self, other):
1894
1883
return result
1895
1884
1896
1885
def get_year_end (self , dt ):
1897
- if self .variation == "nearest" :
1898
- return self ._get_year_end_nearest (dt )
1899
- else :
1900
- return self ._get_year_end_last (dt )
1901
-
1902
- def get_target_month_end (self , dt ):
1903
- target_month = datetime (dt .year , self .startingMonth , 1 ,
1904
- tzinfo = dt .tzinfo )
1905
- return shift_month (target_month , 0 , 'end' )
1906
- # TODO: is this DST-safe?
1886
+ assert dt .tzinfo is None
1907
1887
1908
- def _get_year_end_nearest ( self , dt ):
1909
- target_date = self . get_target_month_end (dt )
1888
+ dim = ccalendar . get_days_in_month ( dt . year , self . startingMonth )
1889
+ target_date = datetime (dt . year , self . startingMonth , dim )
1910
1890
wkday_diff = self .weekday - target_date .weekday ()
1911
1891
if wkday_diff == 0 :
1892
+ # year_end is the same for "last" and "nearest" cases
1912
1893
return target_date
1913
1894
1914
- days_forward = wkday_diff % 7
1915
- if days_forward <= 3 :
1916
- # The upcoming self.weekday is closer than the previous one
1917
- return target_date + timedelta (days_forward )
1918
- else :
1919
- # The previous self.weekday is closer than the upcoming one
1920
- return target_date + timedelta (days_forward - 7 )
1895
+ if self .variation == "last" :
1896
+ days_forward = (wkday_diff % 7 ) - 7
1921
1897
1922
- def _get_year_end_last (self , dt ):
1923
- current_year = datetime (dt .year , self .startingMonth , 1 ,
1924
- tzinfo = dt .tzinfo )
1925
- return current_year + self ._offset_lwom
1898
+ # days_forward is always negative, so we always end up
1899
+ # in the same year as dt
1900
+ return target_date + timedelta (days = days_forward )
1901
+ else :
1902
+ # variation == "nearest":
1903
+ days_forward = wkday_diff % 7
1904
+ if days_forward <= 3 :
1905
+ # The upcoming self.weekday is closer than the previous one
1906
+ return target_date + timedelta (days_forward )
1907
+ else :
1908
+ # The previous self.weekday is closer than the upcoming one
1909
+ return target_date + timedelta (days_forward - 7 )
1926
1910
1927
1911
@property
1928
1912
def rule_code (self ):
0 commit comments