So assuming that by REF_DATE you mean the variable INDEX_DATE.
Let's also correct your example to more closely match your problem description (and represent the dates in YMD order to avoid confusing the number of the month with the day of the month).
data have;
input ID :$20. (Index_date Date_event) (:yymmdd.) Event :$20. Flag :$20.;
format Index_date Date_event yymmdd10.;
cards;
0001 2024-09-01 2024-10-11 Y 3M
0001 2024-09-01 2024-11-11 Y 3M
0001 2024-09-01 . N .
0001 2024-09-01 2025-01-15 Y 6M
0002 2016-09-11 2017-04-15 Y 9M
0003 2025-06-30 2025-02-09 Y .
0003 2025-06-30 2025-12-12 Y 6M
0004 2024-12-03 . N .
;
So we can use the INTCK() function to check the number of month boundaries crossed. I have chosen to use the continuous method instead of testing for when it crosses day one of the month. But you also might want to use a fixed number of days instead to avoid the fact that calendar months are not all the same length.
To convert from number of months to your 3,6,9,... values you can use the CEIL() function.
data want;
set have;
after = (date_event > index_date);
if after then diff = intck('month',index_date,date_event,'c');
diff3 = 3*ceil(diff/3);
run;
Results
... View more