Appreciate any help you can give.
I'm interested in determining UTD status of a cohort.
I inherited code where I can determine UTD status by a certain age.
I want to compare freq UTD at one date vs. a later date, using same age criteria (EX: must receive 4th dose by 4th birthday or must receive 5 doses at any age).
Here is the code I have which I tweaked based on the code I inherited:
...data is imported and dates are converted to sas dates;
*--define cutoff date;
cutoff='31-AUG-2010'd;
*--determine if kids received 4th dtp dose or after 4th bday (calculated
as 1461) or 5 doses at any age;
1461<=(dtp4-bdate)<=cutoff or 0<=(dtp5-bdate)<=cutoff then cutoff_dtp=1;
....
I run the program a 2nd time using a later cutoff date, below and compare the frequency where cutoff_dtp=1
cutoff='15-FEB-2011'd;
But I am getting the same freq of the UTD status variable 'cutoff_dtp'. It could be possible that no additional kids got vaccinated between the first date and later date.
For one kid:
SAS dates based on Aug 31, 2010 cutoff:
bdate =16641
dtp4=17145
cutoff= 18505
SAS dates based on Feb 15, 2011 cutoff:
bdate =16641
dtp4=17145
cutoff= 18673
Is this the right way to do it or am I missing something? Thanks!
With the criteria straigtened out we'll be talking the same language more or less.
Cutoff represents the following: we want to know the number of kids up to date before school starts and then want to know the number of kids up to date after school has been in session for a few months.
If you want to compare to a date then you need another date value. Modifying the orginal code then the criteria for after 4th birthday would be
if (1461<=(dtp4-bdate) AND dtp4 <= cutoff) or (not missing(dtp5) and dtp5< cutoff) then
cutoff_dtp=1;
By the way for this site it may be better to use the le, lt, ge, gt instead of the symbols as some constructs interfere with the html.
The original program then used age in months (variable is agemonths=(30.4375)*(age in months)) to determine if kid is UTD at a certain age in months. But, I just replaced the agemonths with a cutoff date. Does that make sense? Thanks!
0<=(dtp4-bdate)<=agemonths
Without knowing how age in months was calculated I can't help much but I would say who ever wrote the original code was either translating from another language and being somewhat lazy or not really familiar with how SAS stores dates. But since age in months I would expect to be in 0 to 60 range (60=5 years) then you have the same aritmetic problem that dtp4-bdate is a value in DAYS and would only be true when dtp4 was withing about 60 days of birth which shouldn't be happening.
Date values compare to dates but know when you do arithematic that the results are in other units and should be compared to dates.
Does it make more sense if the age were in months? I ask only because the original program uses age in months. Can you help me understand the difference between age in months vs age in years in relation to the value bdate=16641
Do you want calendar months/years or biologic months/years?
A calendar age in years can be calculated where dob is date of birth date is the date of an occurence of interest, ie. dtp4. and both DOB and other date are SAS date values or a date literal.
ageyear = floor((intck('month',dob,date)- (day(date) < day(dob))) / 12);
And a calendar age in months.
agemonths = intck('month',dob,dov) - (day(dov) < day(dob));
I suspect the original code used age in months because a calendar year age doesn't change for 364 or 365 days and doesn't align well with the dose schedule.
You could get the calendar age in months at cutoff using
agedtp4months = intck('month',dob,&cutoff) - (day(&cutoff) < day(dob));
and possibly use that in comparison
if (agedtp4months ge 48) or (not missing(dtp5) and dtp5< cutoff) then cutoff_dtp=1;
After debugging with a range of dtp4 , dtp5 and cutoff dates to validate the logic you
could move the agedtprmonths assigment code line into the Cutoff_dtp assignment. But have the agedtp4months value around lets you double check.
The biological age in months would the SAS date value divided by 30.4375 which should be at least close the average number of days in a month. But you would still have to compare the dtp4 date with cutoff
if ((dtp4/30.437) ge 48 and dtp4 le cutoff ) or ...
I think your problem lies with cutoff. For practically any reasonable value of dtp4, dtp5 and birthdate you'll get values of 0 to around 2000. The value of cutoff is the SAS date which is the number of days since 1/1/1960. So all of your values are going to be less than cutoff.
1461<=(dtp4-bdate)<=cutoff maybe should be 0 <= (dtp4-bdate) <= 1461 to get doses within 4 years of birth. You don't say anything about values of dtp5 but if they are missing if not given, the requirement of 5th dose at any age should be "or not missing(dtp5)".
If you have some other value as a placeholder for missing values in dtp5 then "or dtp ne value"
Can you help me understand what you mean by 0 to 2000?
For example, one bdate is July 24, 2005 which translates to a sas date of 16641.
Also we want to get doses after the 4th bday (vs within birth to 4th bday).
Can you help me understand what you meant by the dtp5
If they're missing the 5th of dtp and didn't receive the 4th dose on or after the 4th bday then they are not UTD.
Thanks!
2000 / 365.25 is roughly 5.5 years. If you are looking at children upto age 10 then the difference between the birthdate and the dose date is only 3652 days (ie dtp4-bdate values which is what you have compared to cutoff). When your cuttoff is 18505 then 18505/365.25 is looking for a difference of 50.6 years. ALL of your dosedate-birthdate are likely to be less than 50 years. Especially since the requirement for 4 or more doses of DTap is relatively recent when compared to 50 years.
In your example:
bdate =16641
dtp4=17145
cutoff= 18505
17145-16641=504 so the first part of your comparison would be false but unless you subject is over 50 then
0<=(dtp5-bdate)<=cutoff is going to be true for every record so with the OR part false or true = true and every singel record will set cutoff_dtp=1 unless dtp5 is missing when the age is greater than 4 years.
What exactly is your cutoff supposed to represent? If it is the latest date for dtp4 then your code needs something like
if 1461<=(dtp4-bdate) and dtp4 <= cutoff
Also this quote from the initial post "must receive 4th dose by 4th birthday or must receive 5 doses at any age)." usually means that the 4th dose is before or at the 4th birthday but now you say "want to get doses after the 4th bday (vs within birth to 4th bday)." So your initial question has a flaw. Until we get which of these is what you actually want it may be hard to answer.
Also you may be better off calculating an age at a specific date or dates as code with magic numbers like 1461 is not easy to interpret or follow in undocumented or poorly documented code.
Biologic age in years at a date could be either age= (date - birthdate)/365.25; which you could round or truncate as needed.You can also use date functions if you need a calendar age.
Then suppose you have age at dtp4 the agedtp4 = (dtp4 - bdate)/356.25; Agedtp5 = (dtp5/bdate)/365/25;
Criteria for DTP is 4 doses with the 4th dose on or after the 4th bday or 5 doses at any age; apologies for the confusion and inconsistency in criteria.
Cutoff represents the following: we want to know the number of kids up to date before school starts and then want to know the number of kids up to date after school has been in session for a few months.
Does it make more sense if the age were in months? I ask only because the original program uses age in months. Can you help me understand the difference between age in months vs age in years in relation to the value bdate=16641
The original date SAS is pulling from in the database is a 2-digit month, 2-digit day, and 2-digit year (so, for July 24, 2005, the three fields are 07 24 05. Then, the program converts to a SAS date using sasdate=mdy(month, day, year).
The original program then used age in months (variable is agemonths=(30.4375)*(age in months)) to determine if kid is UTD at a certain age in months. But, I just replaced the agemonths with a cutoff date. Does that make sense? Thanks!
0<=(dtp4-bdate)<=agemonths
With the criteria straigtened out we'll be talking the same language more or less.
Cutoff represents the following: we want to know the number of kids up to date before school starts and then want to know the number of kids up to date after school has been in session for a few months.
If you want to compare to a date then you need another date value. Modifying the orginal code then the criteria for after 4th birthday would be
if (1461<=(dtp4-bdate) AND dtp4 <= cutoff) or (not missing(dtp5) and dtp5< cutoff) then
cutoff_dtp=1;
By the way for this site it may be better to use the le, lt, ge, gt instead of the symbols as some constructs interfere with the html.
The original program then used age in months (variable is agemonths=(30.4375)*(age in months)) to determine if kid is UTD at a certain age in months. But, I just replaced the agemonths with a cutoff date. Does that make sense? Thanks!
0<=(dtp4-bdate)<=agemonths
Without knowing how age in months was calculated I can't help much but I would say who ever wrote the original code was either translating from another language and being somewhat lazy or not really familiar with how SAS stores dates. But since age in months I would expect to be in 0 to 60 range (60=5 years) then you have the same aritmetic problem that dtp4-bdate is a value in DAYS and would only be true when dtp4 was withing about 60 days of birth which shouldn't be happening.
Date values compare to dates but know when you do arithematic that the results are in other units and should be compared to dates.
Does it make more sense if the age were in months? I ask only because the original program uses age in months. Can you help me understand the difference between age in months vs age in years in relation to the value bdate=16641
Do you want calendar months/years or biologic months/years?
A calendar age in years can be calculated where dob is date of birth date is the date of an occurence of interest, ie. dtp4. and both DOB and other date are SAS date values or a date literal.
ageyear = floor((intck('month',dob,date)- (day(date) < day(dob))) / 12);
And a calendar age in months.
agemonths = intck('month',dob,dov) - (day(dov) < day(dob));
I suspect the original code used age in months because a calendar year age doesn't change for 364 or 365 days and doesn't align well with the dose schedule.
You could get the calendar age in months at cutoff using
agedtp4months = intck('month',dob,&cutoff) - (day(&cutoff) < day(dob));
and possibly use that in comparison
if (agedtp4months ge 48) or (not missing(dtp5) and dtp5< cutoff) then cutoff_dtp=1;
After debugging with a range of dtp4 , dtp5 and cutoff dates to validate the logic you
could move the agedtprmonths assigment code line into the Cutoff_dtp assignment. But have the agedtp4months value around lets you double check.
The biological age in months would the SAS date value divided by 30.4375 which should be at least close the average number of days in a month. But you would still have to compare the dtp4 date with cutoff
if ((dtp4/30.437) ge 48 and dtp4 le cutoff ) or ...
Appreciate you breaking down the different issues and explaining the difference between months and years
Totally makes sense now!!!! Thank you!!
I thought I understood but can you help me understand this part:
- (day(&cutoff) < day(dob));
I get the first part: intck calcluates the number of months between dob and the cutoff. But what does the second part do(the subtraction part)?
It is part of the code created below:
You could get the calendar age in months at cutoff using
agedtp4months = intck('month',dob,&cutoff) - (day(&cutoff) < day(dob));
Thanks!
Thanks!
The last part is to reduce the month count by if the day of the month of birth is after that of your date.
Suppose your cutoff is 15APR2013 and the birth date is 22APR2009. Since the 22 is after the 15th you haven't reached a full calendar month for typical age reports. So it subtracts 1 (the value of a true result from the compariso) from the number of months.
Why doesn't SAS automatically do it in the INTCK Function?
INTCK counts calendar boundary intervals. Check the result of x= intck('month','30Jun2014'd,'01JUL204'd);
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 16. Read more here about why you should contribute and what is in it for you!
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.
Select SAS Training centers are offering in-person courses. View upcoming courses for: