This can be done in a single data step, by reading each ID twice, once to get the counts, second time to output the original data with those counts.
data have;
infile cards expandtabs;
input ID Date :yymmdd12.;
format Date yymmdd10.;
cards;
1 2016-04-15
1 2016-04-20
3 2016-04-29
3 2016-04-21
3 2016-04-25
4 2017-12-17
;
data want (drop=_: nxt_:);
do until (id^=nxt_id);
do _ntrans=1 by 1 until (intck('month',date,nxt_date)^=0 or id^=nxt_id);
merge have
have (firstobs=2 keep=id date rename=(id=nxt_id date=nxt_date));
array mnths{4:12} april_trans _unwanted5-_unwanted11 dec_trans;
end;
mnths{month(date)}=_ntrans;
end;
do _m=4,12; if mnths{_m}=. then mnths{_m}=0; end;
do until (last.id);
set have;
by id notsorted;
output;
end;
run;
This program assumes that the data are grouped by id and within id, grouped by month. The ID's (and the months within ID's) need not be in ascending order. The technique in determining month and/or id boundaries is in the merge statement, using the "firstobs=2" parameter for one of the merged data sequences.
It uses the ARRAY statement to index the array MNTHS by month number. Since you only want April and December, the array has lower index of 4 and upper index of 12. And it has a bunch of unwanted variables as placeholders for May through November. If you want other months just make changes to the variable names and/or array index range. And modify the "do _m=4,12;" loop accordingly. It wouldn't be hard to use the array for months ranging over multiple years - just add a second dimension for year.
... View more