End of current anniversary year
This is the recommended expression for rounding dates to the end of the current anniversary year:
AnyBOY_DT:= 4/23/1956 & ; any beginning of anniversary date
EOY_DT:= {AnyBOY_DT #DATEPLUS ((1 + #FLOOR (A_DT #YEARDIF AnyBOY_DT))*1Y)} - 1 &
A_DT may be either a single date (e.g., 7/16/2015, DOH, #DODEC) or an array of dates (e.g., #DATE).
#FLOOR (A_DT #YEARDIF AnyBOY_DT) calculates the completed years between A_DT and AnyBOY_DT. Then adding 1 more year, (1 + #FLOOR ...), gives us the completed years between AnyBOY_DT and the beginning of the anniversary year after A_DT. Now, adding the completed year difference back to AnyBOY_DT (using #DATEPLUS) gives us the beginning of the next anniversary year. Subtracting 1 day gives us the end of the current anniversary year.
Please note that if AnyBOY_DT is a leap date (e.g., 2/29/1956), then the beginning of the next anniversary dates will be 2/29 in leap years and 3/1 in non-leap years: when you add any number of years (NOT divisible by 4) to a leap date, then you end up with 3/1 date (when using #DATEPLUS). For example, 2/29/2004 #DATEPLUS 1Y is 3/1/2005, 2/29/2004 #DATEPLUS 2Y is 3/1/2006, 2/29/2004 #DATEPLUS 3Y is 3/1/2007, and 2/29/2004 #DATEPLUS 4Y is 2/29/2008.
If you want the beginning of the next anniversary date to be 2/29 in leap years and 2/28 in non-leap years, then you need to add a leap anniversary date adjustment to the expression:
AnyBOY_DT:= 4/23/1956 & ; any beginning of anniversary date
BOY1_DT:= AnyBOY_DT #DATEPLUS (1 + (#FLOOR (A_DT #YEARDIF AnyBOY_DT))*1Y) &
BOY1_DT:= BOY1_DT - {(#MONTH AnyBOY_DT) <> (#MONTH BOY1_DT)} & ; leap anniversary date adjustment (if any)
EOY_DT:= BOY1_DT - 1 &
The special adjustment for 2/29 anniversary dates (the 2nd to last line in the above expression), subtracts 1 day when the month of the calculated beginning of the next anniversary year (e.g., BOY_DT) is different from the month of AnyBOY_DT (i.e., the "any beginning of anniversary year" date). This converts all the non-leap year beginning of the next anniversary year 3/1 dates to 2/28 dates. Then, subtracting 1 day gives us the end of the current anniversary year.
Note that if the next beginning anniversary date (i.e., AnyBOY_DT) is a 2/28 date (regardless if it's in a leap year or non-leap year), adding any number of years to your 2/28 anniversary date is always a 2/28 date. If that's not what you want, then start with a leap date (e.g., 2/29/1956) and use the special 2/29 anniversary adjustment.