@@ -3757,16 +3757,22 @@ cdef shift_quarters(
3757
3757
n = quarters
3758
3758
3759
3759
months_since = (dts.month - q1start_month) % modby
3760
+ compare_day = get_day_of_month(& dts, day_opt)
3760
3761
3761
3762
# offset semantics - if on the anchor point and going backwards
3762
3763
# shift to next
3763
3764
if n <= 0 and (months_since != 0 or
3764
- (months_since == 0 and dts.day > 1 )):
3765
+ (months_since == 0 and dts.day > compare_day)):
3766
+ # make sure to roll forward, so negate
3765
3767
n += 1
3768
+ elif n > 0 and (months_since == 0 and dts.day < compare_day):
3769
+ # pretend to roll back if on same month but
3770
+ # before compare_day
3771
+ n -= 1
3766
3772
3767
3773
dts.year = year_add_months(dts, modby * n - months_since)
3768
3774
dts.month = month_add_months(dts, modby * n - months_since)
3769
- dts.day = 1
3775
+ dts.day = get_day_of_month( & dts, day_opt)
3770
3776
3771
3777
out[i] = dtstruct_to_dt64(& dts)
3772
3778
@@ -3781,21 +3787,20 @@ cdef shift_quarters(
3781
3787
n = quarters
3782
3788
3783
3789
months_since = (dts.month - q1start_month) % modby
3790
+ compare_day = get_day_of_month(& dts, day_opt)
3784
3791
3785
- if n <= 0 and months_since != 0 :
3786
- # The general case of this condition would be
3787
- # `months_since != 0 or (months_since == 0 and
3788
- # dts.day > get_days_in_month(dts.year, dts.month))`
3789
- # but the get_days_in_month inequality would never hold.
3792
+ if n <= 0 and (months_since != 0 or
3793
+ (months_since == 0 and dts.day > compare_day)):
3794
+ # make sure to roll forward, so negate
3790
3795
n += 1
3791
- elif n > 0 and (months_since == 0 and
3792
- dts.day < get_days_in_month(dts.year,
3793
- dts.month)):
3796
+ elif n > 0 and (months_since == 0 and dts.day < compare_day):
3797
+ # pretend to roll back if on same month but
3798
+ # before compare_day
3794
3799
n -= 1
3795
3800
3796
3801
dts.year = year_add_months(dts, modby * n - months_since)
3797
3802
dts.month = month_add_months(dts, modby * n - months_since)
3798
- dts.day = get_days_in_month( dts.year, dts.month )
3803
+ dts.day = get_day_of_month( & dts, day_opt )
3799
3804
3800
3805
out[i] = dtstruct_to_dt64(& dts)
3801
3806
@@ -3812,7 +3817,7 @@ cdef shift_quarters(
3812
3817
months_since = (dts.month - q1start_month) % modby
3813
3818
# compare_day is only relevant for comparison in the case
3814
3819
# where months_since == 0.
3815
- compare_day = get_firstbday( dts.year, dts.month )
3820
+ compare_day = get_day_of_month( & dts, day_opt )
3816
3821
3817
3822
if n <= 0 and (months_since != 0 or
3818
3823
(months_since == 0 and dts.day > compare_day)):
@@ -3826,7 +3831,7 @@ cdef shift_quarters(
3826
3831
dts.year = year_add_months(dts, modby * n - months_since)
3827
3832
dts.month = month_add_months(dts, modby * n - months_since)
3828
3833
3829
- dts.day = get_firstbday( dts.year, dts.month )
3834
+ dts.day = get_day_of_month( & dts, day_opt )
3830
3835
3831
3836
out[i] = dtstruct_to_dt64(& dts)
3832
3837
@@ -3843,7 +3848,7 @@ cdef shift_quarters(
3843
3848
months_since = (dts.month - q1start_month) % modby
3844
3849
# compare_day is only relevant for comparison in the case
3845
3850
# where months_since == 0.
3846
- compare_day = get_lastbday( dts.year, dts.month )
3851
+ compare_day = get_day_of_month( & dts, day_opt )
3847
3852
3848
3853
if n <= 0 and (months_since != 0 or
3849
3854
(months_since == 0 and dts.day > compare_day)):
@@ -3857,7 +3862,7 @@ cdef shift_quarters(
3857
3862
dts.year = year_add_months(dts, modby * n - months_since)
3858
3863
dts.month = month_add_months(dts, modby * n - months_since)
3859
3864
3860
- dts.day = get_lastbday( dts.year, dts.month )
3865
+ dts.day = get_day_of_month( & dts, day_opt )
3861
3866
3862
3867
out[i] = dtstruct_to_dt64(& dts)
3863
3868
@@ -3909,7 +3914,7 @@ def shift_months(const int64_t[:] dtindex, int months, object day_opt=None):
3909
3914
3910
3915
dt64_to_dtstruct(dtindex[i], & dts)
3911
3916
months_to_roll = months
3912
- compare_day = 1
3917
+ compare_day = get_day_of_month( & dts, day_opt)
3913
3918
3914
3919
# offset semantics - if on the anchor point and going backwards
3915
3920
# shift to next
@@ -3918,7 +3923,7 @@ def shift_months(const int64_t[:] dtindex, int months, object day_opt=None):
3918
3923
3919
3924
dts.year = year_add_months(dts, months_to_roll)
3920
3925
dts.month = month_add_months(dts, months_to_roll)
3921
- dts.day = 1
3926
+ dts.day = get_day_of_month( & dts, day_opt)
3922
3927
3923
3928
out[i] = dtstruct_to_dt64(& dts)
3924
3929
elif day_opt == " end" :
@@ -3930,7 +3935,7 @@ def shift_months(const int64_t[:] dtindex, int months, object day_opt=None):
3930
3935
3931
3936
dt64_to_dtstruct(dtindex[i], & dts)
3932
3937
months_to_roll = months
3933
- compare_day = get_days_in_month( dts.year, dts.month )
3938
+ compare_day = get_day_of_month( & dts, day_opt )
3934
3939
3935
3940
# similar semantics - when adding shift forward by one
3936
3941
# month if already at an end of month
@@ -3940,7 +3945,7 @@ def shift_months(const int64_t[:] dtindex, int months, object day_opt=None):
3940
3945
dts.year = year_add_months(dts, months_to_roll)
3941
3946
dts.month = month_add_months(dts, months_to_roll)
3942
3947
3943
- dts.day = get_days_in_month( dts.year, dts.month )
3948
+ dts.day = get_day_of_month( & dts, day_opt )
3944
3949
out[i] = dtstruct_to_dt64(& dts)
3945
3950
3946
3951
elif day_opt == " business_start" :
@@ -3952,15 +3957,15 @@ def shift_months(const int64_t[:] dtindex, int months, object day_opt=None):
3952
3957
3953
3958
dt64_to_dtstruct(dtindex[i], & dts)
3954
3959
months_to_roll = months
3955
- compare_day = get_firstbday( dts.year, dts.month )
3960
+ compare_day = get_day_of_month( & dts, day_opt )
3956
3961
3957
3962
months_to_roll = roll_convention(dts.day, months_to_roll,
3958
3963
compare_day)
3959
3964
3960
3965
dts.year = year_add_months(dts, months_to_roll)
3961
3966
dts.month = month_add_months(dts, months_to_roll)
3962
3967
3963
- dts.day = get_firstbday( dts.year, dts.month )
3968
+ dts.day = get_day_of_month( & dts, day_opt )
3964
3969
out[i] = dtstruct_to_dt64(& dts)
3965
3970
3966
3971
elif day_opt == " business_end" :
@@ -3972,15 +3977,15 @@ def shift_months(const int64_t[:] dtindex, int months, object day_opt=None):
3972
3977
3973
3978
dt64_to_dtstruct(dtindex[i], & dts)
3974
3979
months_to_roll = months
3975
- compare_day = get_lastbday( dts.year, dts.month )
3980
+ compare_day = get_day_of_month( & dts, day_opt )
3976
3981
3977
3982
months_to_roll = roll_convention(dts.day, months_to_roll,
3978
3983
compare_day)
3979
3984
3980
3985
dts.year = year_add_months(dts, months_to_roll)
3981
3986
dts.month = month_add_months(dts, months_to_roll)
3982
3987
3983
- dts.day = get_lastbday( dts.year, dts.month )
3988
+ dts.day = get_day_of_month( & dts, day_opt )
3984
3989
out[i] = dtstruct_to_dt64(& dts)
3985
3990
3986
3991
else :
@@ -4051,7 +4056,7 @@ def shift_month(stamp: datetime, months: int,
4051
4056
return stamp.replace(year = year, month = month, day = day)
4052
4057
4053
4058
4054
- cdef int get_day_of_month(npy_datetimestruct* dts, day_opt) nogil except ? - 1 :
4059
+ cdef inline int get_day_of_month(npy_datetimestruct* dts, day_opt) nogil except ? - 1 :
4055
4060
"""
4056
4061
Find the day in `other`'s month that satisfies a DateOffset's is_on_offset
4057
4062
policy, as described by the `day_opt` argument.
0 commit comments