@Reeza
Below is the closest I got using your approach. Ignore, negative survival for ID=3. Please comment if you find another problem.
data have1; set have;
if dx_month = 99 and dx_day = 99 then fake_dx=mdy(1,1,dx_year);
else
if dx_day eq 99 and dx_month ne 99 then
fake_dx=mdy(dx_month,1,dx_year);
run;
data want;
set have1;
*calculate censor date;
censor_date=mdy(censor_month, censor_day, censor_year);
*handle missing values for both day and month;
if dx_month = 99 and dx_day = 99 then
do;
*first possible date is the beginning of the known year of diagnosis;
first_possible_date=intnx('year', fake_dx, 0, 'b');
*last possible date is the earlier of the end of the known year of diagnosis or censoring date;
last_possible_date=min(intnx('year', first_possible_date, 0, 'e'),
censor_date - 1);
*event date is a random date between these dates;
event_date=rand('integer', first_possible_date, last_possible_date);
*assign day and months as needed;
dx_month=month(event_date);
dx_day=day(event_date);
end;
else if dx_day eq 99 and dx_month ne 99 then
do;
*first possible date is beginning of the known month of diagnosis;
first_possible_date=mdy(dx_month, 1, dx_year);
*last possible date is last day of the of month;
*EXCEPT if month is same as censor month;
*in that case, use the earlier of the two dates;
last_possible_date=min(intnx('month', first_possible_date, 0, 'e'),
censor_date - 1);
*calculate a random event date;
event_date=rand('integer', first_possible_date, last_possible_date);
*assign day as needed;
dx_day=day(event_date);
end;
else
event_date=mdy(dx_month, dx_day, dx_year);
*format dates for display and legibility;
format censor event_date first_possible_date last_possible_date fake_dx date9.;
check = censor_date - event_date;
run;
proc print data=want(drop=censor_:);
run;
... View more