Hi:
This is the Stata User Formerly Known As an SPSS Macro Programmer (SUFKASP). Since SPSS 13 I use(d) DATEDIF to compute age from two dates. Stata users seem to keep on using the old formula: int(StudyDate-DateOfBirth)/365.25 (since Stata stores dates as days, it is easier than the SPSS counterpart, that required CTIME.DAYS to convert seconds to days). I recall that years ago we had an interesting thread concerning the errors this method could cause in some cases. I had and slightly improved version: INT(CTIME.DAYS(1+StudyDate-DateOfBirth)/365.25) That avoided some errors, but not all of them. There was a short syntax that computed ages correctly before SPSS 13. It looks that I did not keep a copy of it (bad idea..) because of DATEDIF. I would like to have it again to translate it to a Stata do file. Does anybody keep it yet? Thanks in advance Marta GG (SUFKASP) ===================== To manage your subscription to SPSSX-L, send a message to [hidden email] (not to SPSSX-L), with no body text except the command. To leave the list, send the command SIGNOFF SPSSX-L For a list of commands to manage subscriptions, send the command INFO REFCARD |
Hi Marta
About ten years ago I ran into this problem with dates, and after some web research on calendars and date calculations (especially reliant on a web page of handy hints from an SPSS-using researcher from NZ) came up with a couple of approaches : As you discovered, the usual method falls over on anniversaries. Often this isn't a problem, but there are some purposes where it is important to be able to state whether someone is above or below a critical age in years. In my former employment preparing statistics on criminal justice, it was important to know whether offenders were to be treated as juveniles by the courts, and whether victims were in particular age brackets (for the purposes of sentencing), so avoiding being even a day out in the age calculation was critical. do if ((STARTMTH eq ENDMTH) and (STARTDAY eq ENDDAY)) + compute LNTHYRS = rnd((ENDDATE - STARTDAT)/(24*60*60*365.2425)) else + compute LNTHYRS = trunc((ENDDATE - STARTDAT)/(24*60*60*365.2425)) end if Notes: (1) the correct number of days in the average year, to account for leap years, is 365.2425, not 365.25. There are in fact fewer than one leap year every four years, because there are exceptions applied to century years such as 2000. Using 365.25 for the number of days in a year is the system used in the superseded Julian calendar, whereas the Gregorian calendar we now use employs 365.2425. (2) you can substitute 86400 (the number of seconds in a year) for the 24*60*60 calculation, to make it more efficient. (3) if you don't want to bother with the conversion into days of the time difference between the dates, you can use the CTIME.DAYS function, applied to each of the two dates, and omit the 24*60*60 calculation. The first part of the statement above handles the special case of anniversaries, where the result in years, prior to rounding, will be almost exactly the correct number of years, but slightly smaller. Rounding it to the nearest year gives the correct answer. For example if the two dates were January 1st 1900 and January 1st 1901, the difference in years, prior to rounding, is 0.9993361.. Rounded to the nearest year, it gives the correct answer of one year, whilst if you truncate it, you get the incorrect answer of zero. Dates which are not anniversaries are handled by the second part of the conditional, which gives the correct result. A second method There is another way of performing the calculation. It is no shorter than the above one, in terms of lines of code, but it may appeal to some because it works in the same way as we do in everyday life when working out how many years there are between two dates. It works by finding out first if the second date (the end date) is later in the year than (or on the same day as) the first date. If it is, you can just subtract the first year from the second year and the answer is the number of years between them. If it is earlier, you take one off the difference. As in the previous example, the code below assumes you have variables representing the month and day part of the dates concerned. do if ((ENDMTH ge STARTMTH) and (ENDDAY ge STARTDAY)) + compute LNTHYRS = ENDYR - STARTYR else + compute LNTHYRS = ENDYR - STARTYR -1 end if Note: (1) if you don't want to bother with storing the year, day and month portions of a date you can use the XDATE.YEAR, XDATE.MDAY and XDATE.MONTH functions, applied to the relevant date variables. (2) Another way of doing the check on whether the second date is earlier or later in the year than the first is to combine the month and day like this : compute STRT = (100*STARTMTH) + STARTDAY compute END = (100*ENDMTH) + ENDDAY Whichever date is later in the year will produce the bigger number. Thus, for example, the 29th of June becomes 629 and the 30th becomes 630. So in the example above, the first line would become : do if (END ge START) Note how the comparison of the two dates is a test of whether the end date is greater than or equal to the start, thus allowing for anniversaries, which have to be accommodated in much the same way as in the original method. It's a long time since I wrote the above notes, so I hope I haven't made any silly blunders in there. I hope this helps Regards, Adrian Adrian Barnett Project Officer Educational Measurement and Analysis Data and Information Systems Department for Education and Child Development "Children and young people are at the centre of everything we do" -----Original Message----- From: SPSSX(r) Discussion [mailto:[hidden email]] On Behalf Of Marta García-Granero Sent: Thursday, 6 December 2012 1:29 AM To: [hidden email] Subject: Old code to compute age from dates (was it Art Kendall's?) Hi: This is the Stata User Formerly Known As an SPSS Macro Programmer (SUFKASP). Since SPSS 13 I use(d) DATEDIF to compute age from two dates. Stata users seem to keep on using the old formula: int(StudyDate-DateOfBirth)/365.25 (since Stata stores dates as days, it is easier than the SPSS counterpart, that required CTIME.DAYS to convert seconds to days). I recall that years ago we had an interesting thread concerning the errors this method could cause in some cases. I had and slightly improved version: INT(CTIME.DAYS(1+StudyDate-DateOfBirth)/365.25) That avoided some errors, but not all of them. There was a short syntax that computed ages correctly before SPSS 13. It looks that I did not keep a copy of it (bad idea..) because of DATEDIF. I would like to have it again to translate it to a Stata do file. Does anybody keep it yet? Thanks in advance Marta GG (SUFKASP) ===================== To manage your subscription to SPSSX-L, send a message to [hidden email] (not to SPSSX-L), with no body text except the command. To leave the list, send the command SIGNOFF SPSSX-L For a list of commands to manage subscriptions, send the command INFO REFCARD ===================== To manage your subscription to SPSSX-L, send a message to [hidden email] (not to SPSSX-L), with no body text except the command. To leave the list, send the command SIGNOFF SPSSX-L For a list of commands to manage subscriptions, send the command INFO REFCARD |
In reply to this post by Marta Garcia-Granero
Hi, Marta!
At 09:58 AM 12/5/2012, Marta García-Granero wrote: >Since SPSS 13 I use(d) DATEDIF to compute age >from two dates. Stata users seem to keep on using the old formula: >int(StudyDate-DateOfBirth)/365.25 (since Stata >stores dates as days, it is easier than the SPSS >counterpart, that required CTIME.DAYS to convert seconds to days). > >I had a slightly improved version: > >INT(CTIME.DAYS(1+StudyDate-DateOfBirth)/365.25) > >That avoided some errors, but not all of them. Since you were using DATEDIFF, it sounds like you're looking for the civil definition of 'age': Age increases by one year at the beginning of the birth date, each year. By that definition, 'years' aren't of uniform length, so the best uniform-length formula (the one you have above) isn't perfect. It's very difficult unless STATA can extract calendar year, month, and day from a date in its format -- but it probably can. Here's old-school SPSS, which I *think* is right, and which should translate into STATA: COMPUTE AgeYears = XDATE.YEAR(StudyDate)-XDATE.YEAR(DateOfBirth). DO IF XDATE.MONTH(StudyDate) LT XDATE.MONTH(DateOfBirth). . COMPUTE AgeYears = AgeYears - 1. ELSE IF XDATE.MONTH(StudyDate) EQ XDATE.MONTH(DateOfBirth). . IF XDATE.MDAY(StudyDate) LT XDATE.MDAY(DateOfBirth) AgeYears = AgeYears - 1. END IF. ===================== To manage your subscription to SPSSX-L, send a message to [hidden email] (not to SPSSX-L), with no body text except the command. To leave the list, send the command SIGNOFF SPSSX-L For a list of commands to manage subscriptions, send the command INFO REFCARD |
In reply to this post by Marta Garcia-Granero
new file.
* this program compares different ways of finding the age on an admission date. *note that cases 2, and 6 have the correct age when the first method is used. data list list / birthdat(adate10) admission(adate10) wanted (f3). begin data. 4/10/1931 4/10/2002 71 4/10/1933 4/10/2002 69 4/10/1932 4/7/2002 69 4/10/1932 4/8/2002 69 4/10/1932 4/9/2002 69 4/10/1932 4/10/2002 70 4/10/1932 4/11/2002 70 4/10/1932 4/12/2002 70 4/10/1932 4/13/2002 70 end data. numeric age_recommended age_wizard age_by_365.25 age_jdate (f3). * recommended method see if birthday in current year has occurred yet. * Rich Ristow posted a more concise way to do this method. compute bmo = xdate.month(birthdat). compute bdom = xdate.mday(birthdat). compute byr = xdate.year(birthdat). compute amo = xdate.month(admission). compute adom = xdate.mday(admission). compute ayr = xdate.year(admission). compute nearbirt = date.mdy(bmo,bdom,ayr). do if nearbirt le admission. compute age_recommended = ayr-byr. else if nearbirt gt admission. compute age_recommended = ayr-byr-1. end if. formats nearbirt (adate10) age_recommended (f3). * Date and Time Wizard: age_wizard. COMPUTE age_wizard = DATEDIF(admission, birthdat, "years"). VARIABLE LABEL age_wizard "age using the wizard". VARIABLE LEVEL age_wizard (SCALE). FORMATS age_wizard (F5.0). VARIABLE WIDTH age_wizard(5). *method by dividing by average days in year. COMPUTE age_by_365.25 = trunc(CTIME.DAYS(admission - birthdat) / 365.25) . * jdate method from earlier responder. compute age_jdate = xdate.year(admission) - xdate.year(birthdat) - ( xdate.jdate(birthdat) gt xdate.jdate(admission) ). compute age_jdate = xdate.year(admission) - xdate.year(birthdat) - ( xdate.jdate(birthdat) gt xdate.jdate(admission) ). compute jadm = xdate.jdate(admission) . compute jborn = xdate.jdate(birthdat) . formats age_jdate jborn jadm(f3). numeric line (f2). compute case = $casenum. list /variables = case admission birthdat wanted age_recommended age_wizard age_by_365.25 age_jdate. Art Kendall Social Research ConsultantsOn 12/5/2012 9:58 AM, Marta García-Granero wrote: Hi: ===================== To manage your subscription to SPSSX-L, send a message to [hidden email] (not to SPSSX-L), with no body text except the command. To leave the list, send the command SIGNOFF SPSSX-L For a list of commands to manage subscriptions, send the command INFO REFCARD
Art Kendall
Social Research Consultants |
Administrator
|
In reply to this post by Richard Ristow
Nice old-school code, Richard. Back in the day, I bet people frequently stuck that in a macro. E.g.,
DEFINE !GetCivilAge (AgeVar = !tokens(1) / Date1 = !tokens(1) / Date2 = !tokens(1)) COMPUTE !AgeVar = XDATE.YEAR(!Date2)-XDATE.YEAR(!Date1). DO IF XDATE.MONTH(!Date2) LT XDATE.MONTH(!Date1). . COMPUTE !AgeVar = !AgeVar - 1. ELSE IF XDATE.MONTH(!Date2) EQ XDATE.MONTH(!Date1). . IF XDATE.MDAY(!Date2) LT XDATE.MDAY(!Date1) !AgeVar = !AgeVar - 1. END IF. EXECUTE. !ENDDEFINE. data list list / DOB StudyDate (2date11). begin data 7-Mar-1960 6-Mar-2012 7-Mar-1960 7-Mar-2012 7-Mar-1960 8-Mar-2012 7-Mar-1960 6-Dec-2012 end data. !GetCivilAge AgeVar = Age1 Date1 = DOB Date2 = StudyDate. * Now compute civil age via DateDiff. compute Age2 = DateDiff(StudyDate,DOB,"years"). formats Age1 Age2 (f5.0). LIST. OUTPUT: DOB StudyDate Age1 Age2 07-MAR-1960 06-MAR-2012 51 51 07-MAR-1960 07-MAR-2012 52 52 07-MAR-1960 08-MAR-2012 52 52 07-MAR-1960 06-DEC-2012 52 52 And to anticipate, the question, no, 7-Mar-1960 is not my DOB. ;-)
--
Bruce Weaver bweaver@lakeheadu.ca http://sites.google.com/a/lakeheadu.ca/bweaver/ "When all else fails, RTFM." PLEASE NOTE THE FOLLOWING: 1. My Hotmail account is not monitored regularly. To send me an e-mail, please use the address shown above. 2. The SPSSX Discussion forum on Nabble is no longer linked to the SPSSX-L listserv administered by UGA (https://listserv.uga.edu/). |
Administrator
|
Nice macro Bruce except I would pull the EXE from the macro.
This might also be one of the rare defensible uses of positional arguments. Could also compact the logic as follows (untested) DEFINE !GetCivilAge (!POS= !tokens(1) / !POS= !tokens(1) / !POS= !tokens(1)) COMPUTE !1= XDATE.YEAR(!3)-XDATE.YEAR(!2). IF XDATE.MONTH(!3) LT XDATE.MONTH(!2) !1= !1- 1. IF XDATE.MONTH(!3) EQ XDATE.MONTH(!2) AND XDATE.MDAY(!2) LT XDATE.MDAY(!2) !1= !1- 1. !ENDDEFINE. !GetCivilAge Age1 DOB StudyDate. Or to get uberweird (again untested): DEFINE !GetCivilAge2 (!POS= !tokens(1) / !POS= !tokens(1) / !POS= !tokens(1)) COMPUTE !1= XDATE.YEAR(!3)-XDATE.YEAR(!2) -(XDATE.MONTH(!3) LT XDATE.MONTH(!2)) -((XDATE.MONTH(!3) EQ XDATE.MONTH(!2)) AND (XDATE.MDAY(!2) LT XDATE.MDAY(!2))) . !ENDDEFINE. !GetCivilAge2 Age1 DOB StudyDate. ==
Please reply to the list and not to my personal email.
Those desiring my consulting or training services please feel free to email me. --- "Nolite dare sanctum canibus neque mittatis margaritas vestras ante porcos ne forte conculcent eas pedibus suis." Cum es damnatorum possederunt porcos iens ut salire off sanguinum cliff in abyssum?" |
Administrator
|
David, good idea to use positional arguments -- that makes the macro call simpler. Something is going awry in your two untested modifications of it though. Age0 below is from my original macro (using Richard's code, and modified to use positional arguments), Age1 and Age2 are from your two untested macros, and Age3 is computed using DateDiff.
Here's the output: DOB StudyDate Age0 Age1 Age2 Age3 07-MAR-1960 06-MAR-2012 51 52 52 51 07-MAR-1960 07-MAR-2012 52 52 52 52 07-MAR-1960 08-MAR-2012 52 52 52 52 07-MAR-1960 06-DEC-2012 52 52 52 52 And here's the syntax that generated it: data list list / DOB StudyDate (2date11). begin data 7-Mar-1960 6-Mar-2012 7-Mar-1960 7-Mar-2012 7-Mar-1960 8-Mar-2012 7-Mar-1960 6-Dec-2012 end data. DEFINE !GetCivilAge (!POS = !tokens(1) / !POS = !tokens(1) / !POS = !tokens(1)) * Richard Ristow's old-school code from SPSSX-L: See the thread called * "Old code to compute age from dates (was it Art Kendall's?)" . COMPUTE !1 = XDATE.YEAR(!3)-XDATE.YEAR(!2). DO IF XDATE.MONTH(!3) LT XDATE.MONTH(!2). . COMPUTE !1 = !1 - 1. ELSE IF XDATE.MONTH(!3) EQ XDATE.MONTH(!2). . IF XDATE.MDAY(!3) LT XDATE.MDAY(!2) !1 = !1 - 1. END IF. !ENDDEFINE. DEFINE !GetCivilAge1 (!POS= !tokens(1) / !POS= !tokens(1) / !POS= !tokens(1)) COMPUTE !1= XDATE.YEAR(!3)-XDATE.YEAR(!2). IF XDATE.MONTH(!3) LT XDATE.MONTH(!2) !1= !1- 1. IF XDATE.MONTH(!3) EQ XDATE.MONTH(!2) AND XDATE.MDAY(!2) LT XDATE.MDAY(!2) !1= !1- 1. !ENDDEFINE. DEFINE !GetCivilAge2 (!POS= !tokens(1) / !POS= !tokens(1) / !POS= !tokens(1)) COMPUTE !1= XDATE.YEAR(!3)-XDATE.YEAR(!2) -(XDATE.MONTH(!3) LT XDATE.MONTH(!2)) -((XDATE.MONTH(!3) EQ XDATE.MONTH(!2)) AND (XDATE.MDAY(!2) LT XDATE.MDAY(!2))) . !ENDDEFINE. !GetCivilAge Age0 DOB StudyDate. !GetCivilAge1 Age1 DOB StudyDate. !GetCivilAge2 Age2 DOB StudyDate. compute Age3 = DateDiff(StudyDate,DOB,"years"). formats Age0 Age1 Age2 Age3 (f5.0). LIST.
--
Bruce Weaver bweaver@lakeheadu.ca http://sites.google.com/a/lakeheadu.ca/bweaver/ "When all else fails, RTFM." PLEASE NOTE THE FOLLOWING: 1. My Hotmail account is not monitored regularly. To send me an e-mail, please use the address shown above. 2. The SPSSX Discussion forum on Nabble is no longer linked to the SPSSX-L listserv administered by UGA (https://listserv.uga.edu/). |
Administrator
|
Doh Brainfart:
AND (XDATE.MDAY(!2) LT XDATE.MDAY(!2))) . I Blame it on the cocktails!!! ;-))) let's try ;-) -- AND (XDATE.MDAY(!3) LT XDATE.MDAY(!2))) . ----- Here is another flavor using !POS which also communicates some semantic intent wrt what is what ;-) -- DEFINE CivilAge (!POS= !Charend("=") / !POS= !ENCLOSE("(",")")). !LET !H=!HEAD(!2) !LET !T=!TAIL(!2) COMPUTE !1= XDATE.YEAR(!T)-XDATE.YEAR(!H) -(XDATE.MONTH(!T) LT XDATE.MONTH(!H)) -((XDATE.MONTH(!T) EQ XDATE.MONTH(!H)) AND (XDATE.MDAY(!T) LT XDATE.MDAY(!H))) . !ENDDEFINE. CivilAge age1 =(dob studydat). Meanwhile, everyone including myself seems to have forgotten about our dear friend XDATE.JDAY Drum Roll.... -- DEFINE CivilAg2 (!POS= !Charend("=") / !POS= !ENCLOSE("(",")")). !LET !H=!HEAD(!2) !LET !T=!TAIL(!2) COMPUTE !1= XDATE.YEAR(!T)-XDATE.YEAR(!H)-(XDATE.JDAY(!T) LT XDATE.JDAY(!H)). !ENDDEFINE. CivilAg2 age2 =(dob studydat). DOB STUDYDAT AGE1 AGE2 07-MAR-1960 06-MAR-2012 51.00 51.00 07-MAR-1960 07-MAR-2012 52.00 52.00 07-MAR-1960 08-MAR-2012 52.00 52.00 07-MAR-1960 06-DEC-2012 52.00 52.00 Number of cases read: 4 Number of cases listed: 4
Please reply to the list and not to my personal email.
Those desiring my consulting or training services please feel free to email me. --- "Nolite dare sanctum canibus neque mittatis margaritas vestras ante porcos ne forte conculcent eas pedibus suis." Cum es damnatorum possederunt porcos iens ut salire off sanguinum cliff in abyssum?" |
Administrator
|
Nice use of XDATE.JDAY, David! From the FM (for those who can't be bothered to look it up):
XDATE.JDAY(datevalue). Numeric. Returns the day of the year (an integer between 1 and 366) from a numeric value that represents a date. The argument can be a number, a date format variable, or an expression that resolves to a date. Getting back to the reason for Marta's original post (i.e., computing civil age in Stata), it looks like the "jtoe" function can be used to extract the day of the year in Stata. http://www.stata.com/products/stb/journals/stb14.pdf ;-)
--
Bruce Weaver bweaver@lakeheadu.ca http://sites.google.com/a/lakeheadu.ca/bweaver/ "When all else fails, RTFM." PLEASE NOTE THE FOLLOWING: 1. My Hotmail account is not monitored regularly. To send me an e-mail, please use the address shown above. 2. The SPSSX Discussion forum on Nabble is no longer linked to the SPSSX-L listserv administered by UGA (https://listserv.uga.edu/). |
In reply to this post by David Marso
At 09:35 AM 12/7/2012, David Marso wrote:
>Everyone including myself seems to have forgotten about our dear >friend XDATE.JDAY: >-- >DEFINE CivilAg2 (!POS= !Charend("=") / !POS= !ENCLOSE("(",")")). >!LET !H=!HEAD(!2) !LET !T=!TAIL(!2) >COMPUTE !1= XDATE.YEAR(!T)-XDATE.YEAR(!H)-(XDATE.JDAY(!T) LT >XDATE.JDAY(!H)). >!ENDDEFINE. Actually, that one was proposed. It's a good solution, with one small glitch: if the birthdate is in March or later, the JDAY of the birthdate will differ by one day between leap years and non-leap years. ===================== To manage your subscription to SPSSX-L, send a message to [hidden email] (not to SPSSX-L), with no body text except the command. To leave the list, send the command SIGNOFF SPSSX-L For a list of commands to manage subscriptions, send the command INFO REFCARD |
Administrator
|
Oh CRAP!
OTOH: CEFGW except for the LCB -- "Actually, that one was proposed. It's a good solution, with one small glitch: if the birthdate is in March or later, the JDAY of the birthdate will differ by one day between leap years and non-leap years."
Please reply to the list and not to my personal email.
Those desiring my consulting or training services please feel free to email me. --- "Nolite dare sanctum canibus neque mittatis margaritas vestras ante porcos ne forte conculcent eas pedibus suis." Cum es damnatorum possederunt porcos iens ut salire off sanguinum cliff in abyssum?" |
At 03:24 PM 12/7/2012, David Marso wrote:
>Oh CRAP! >OTOH: CEFGW except for the LCB All right, I'll bite -- could you expand "CEFGW" and "LCB"? (I'm not aware of any FM (or AM, or NetRadio) I could consult for the information.) ===================== To manage your subscription to SPSSX-L, send a message to [hidden email] (not to SPSSX-L), with no body text except the command. To leave the list, send the command SIGNOFF SPSSX-L For a list of commands to manage subscriptions, send the command INFO REFCARD |
In reply to this post by David Marso
the example
syntax I posted showed that the different
methods gave different results.
To see the problem with the jdate approach eyeball the variable called "wanted" and the variable called "age_jdate" for case #6 Art Kendall Social Research ConsultantsOn 12/7/2012 3:24 PM, David Marso wrote: Oh CRAP! OTOH: CEFGW except for the LCB -- "Actually, that one was proposed. It's a good solution, with one small glitch: if the birthdate is in March or later, the JDAY of the birthdate will differ by one day between leap years and non-leap years." Richard Ristow wroteAt 09:35 AM 12/7/2012, David Marso wrote:Everyone including myself seems to have forgotten about our dear friend XDATE.JDAY: -- DEFINE CivilAg2 (!POS= !Charend("=") / !POS= !ENCLOSE("(",")")). !LET !H=!HEAD(!2) !LET !T=!TAIL(!2) COMPUTE !1= XDATE.YEAR(!T)-XDATE.YEAR(!H)-(XDATE.JDAY(!T) LT XDATE.JDAY(!H)). !ENDDEFINE.Actually, that one was proposed. It's a good solution, with one small glitch: if the birthdate is in March or later, the JDAY of the birthdate will differ by one day between leap years and non-leap years. ===================== To manage your subscription to SPSSX-L, send a message to[hidden email](not to SPSSX-L), with no body text except the command. To leave the list, send the command SIGNOFF SPSSX-L For a list of commands to manage subscriptions, send the command INFO REFCARD----- Please reply to the list and not to my personal email. Those desiring my consulting or training services please feel free to email me. -- View this message in context: http://spssx-discussion.1045642.n5.nabble.com/Old-code-to-compute-age-from-dates-was-it-Art-Kendall-s-tp5716678p5716778.html Sent from the SPSSX Discussion mailing list archive at Nabble.com. ===================== To manage your subscription to SPSSX-L, send a message to [hidden email] (not to SPSSX-L), with no body text except the command. To leave the list, send the command SIGNOFF SPSSX-L For a list of commands to manage subscriptions, send the command INFO REFCARD ===================== To manage your subscription to SPSSX-L, send a message to [hidden email] (not to SPSSX-L), with no body text except the command. To leave the list, send the command SIGNOFF SPSSX-L For a list of commands to manage subscriptions, send the command INFO REFCARD
Art Kendall
Social Research Consultants |
Administrator
|
In reply to this post by Richard Ristow
CEFGW =Close enough for government work.
LCB = Liquor control board ;=)
Please reply to the list and not to my personal email.
Those desiring my consulting or training services please feel free to email me. --- "Nolite dare sanctum canibus neque mittatis margaritas vestras ante porcos ne forte conculcent eas pedibus suis." Cum es damnatorum possederunt porcos iens ut salire off sanguinum cliff in abyssum?" |
In reply to this post by Art Kendall
this is a hopefully
more readable version of the comparison of age
calculation methods.
I first cobbled the syntax for the comparison of age finding methods before datediff was available. I only had age_recommended age_wizard age_by_365.25 age_jdate in the original. Can anybody come up with data examples of birthdate admission and wanted age that get wrong ages from datediff? I thought there were problems using datediff but cannot think of my off the top of my head. If the datediff function has had any changes between versions I am running SPSS 21 64-bit. new file. * this program compares different ways of finding the age on an admission date. * note which cases have the computed age the same as the wanted age. * wanted ages were found by mental math you may want to try a few more pairs of dates. * Rich Ristow noted birthdays based on jdate from March on will be off during leap years. data list list / Birthdate(adate10) admission(adate10) wanted (f3). begin data. 4/10/1931 4/10/2002 71 4/10/1933 4/10/2002 69 4/10/1932 4/07/2002 69 4/10/1932 4/08/2002 69 4/10/1932 4/09/2002 69 4/10/1932 4/10/2002 70 4/10/1932 4/11/2002 70 4/10/1932 4/12/2002 70 4/10/1932 4/13/2002 70 3/01/1932 3/01/2003 71 3/01/1932 3/01/2004 72 3/01/1933 3/01/2003 70 3/01/1933 3/01/2004 71 3/01/1933 2/29/2004 70 end data. numeric age_recommended age_datediff age_by_365.25 age_jdate (f3). * recommended method is to see if birthday in current year has occurred yet. *. compute Birth_month = xdate.month(Birthdate). compute Birth_day_of_month = xdate.mday(Birthdate). compute Birth_year = xdate.year(Birthdate). compute Admit_month = xdate.month(admission). compute Admit_day_of_month = xdate.mday(admission). compute Admit_year = xdate.year(admission). *-----. *recommended method of computing age. *note the presence of Admit_year in the next statement. compute admit_year_birthday = date.mdy(Birth_month,Birth_day_of_month,Admit_year). do if admit_year_birthday le admission. compute age_recommended = Admit_year - Birth_year. else if admit_year_birthday gt admission. compute age_recommended = Admit_year - Birth_year - 1. end if. formats admit_year_birthday (adate10) age_recommended (f3). *------. * method using datediff: age_datediff. COMPUTE age_datediff = DATEDIF(admission, Birthdate, "years"). VARIABLE LABEL age_datediff "age using the datediff function". FORMATS age_datediff (F3). *------. *method by dividing elapsed days by average days in year. COMPUTE age_by_365.25 = trunc(CTIME.DAYS(admission - Birthdate) / 365.25) . * jdate method from earlier responder. compute age_jdate = xdate.year(admission) - xdate.year(Birthdate) - ( xdate.jdate(Birthdate) gt xdate.jdate(admission) ). compute jdate_admission = xdate.jdate(admission) . compute jdate_born = xdate.jdate(Birthdate) . formats age_jdate jdate_born jdate_admission(f3). numeric case(f2). compute case = $casenum. list /variables = case Birthdate admission wanted age_recommended age_datediff age_by_365.25 age_jdate. Art Kendall Social Research ConsultantsOn 12/7/2012 4:14 PM, Art Kendall wrote:
===================== To manage your subscription to SPSSX-L, send a message to [hidden email] (not to SPSSX-L), with no body text except the command. To leave the list, send the command SIGNOFF SPSSX-L For a list of commands to manage subscriptions, send the command INFO REFCARD
Art Kendall
Social Research Consultants |
In reply to this post by David Marso
CRAP?
-----Original Message----- From: SPSSX(r) Discussion [mailto:[hidden email]] On Behalf Of David Marso Sent: Friday, December 07, 2012 6:23 PM To: [hidden email] Subject: Re: Old code to compute age from dates (was it Art Kendall's?) CEFGW =Close enough for government work. LCB = Liquor control board ;=) Richard Ristow wrote > At 03:24 PM 12/7/2012, David Marso wrote: > >>Oh CRAP! >>OTOH: CEFGW except for the LCB > > All right, I'll bite -- could you expand "CEFGW" and "LCB"? (I'm not > aware of any FM (or AM, or NetRadio) I could consult for the > information.) > > ===================== > To manage your subscription to SPSSX-L, send a message to > LISTSERV@.UGA > (not to SPSSX-L), with no body text except the command. To leave the > list, send the command SIGNOFF SPSSX-L For a list of commands to > manage subscriptions, send the command INFO REFCARD ----- Please reply to the list and not to my personal email. Those desiring my consulting or training services please feel free to email me. -- View this message in context: http://spssx-discussion.1045642.n5.nabble.com/Old-code-to-compute-age-from-dates-was-it-Art-Kendall-s-tp5716678p5716787.html Sent from the SPSSX Discussion mailing list archive at Nabble.com. ===================== To manage your subscription to SPSSX-L, send a message to [hidden email] (not to SPSSX-L), with no body text except the command. To leave the list, send the command SIGNOFF SPSSX-L For a list of commands to manage subscriptions, send the command INFO REFCARD ===================== To manage your subscription to SPSSX-L, send a message to [hidden email] (not to SPSSX-L), with no body text except the command. To leave the list, send the command SIGNOFF SPSSX-L For a list of commands to manage subscriptions, send the command INFO REFCARD |
In reply to this post by Art Kendall
to wrap this up. the
'recommended method' works as a way to translate to other software/languages.
If I did this correctly, the datediff method matches my old recommended method. input program. loop year = 1899 to 2059 by 1. compute bornmar1 = date.mdy(3,1,year). compute admitbefore = date.mdy(2,28,year+1). compute admitonafter = date.mdy(3, 1,year+1). compute jdate_born = xdate.jdate(bornmar1). compute jdate_admitonafter = xdate.jdate(admitonafter). *-----. *recommended age is 1 if birthday on after admit else 0 . COMPUTE age_datediffbefore = DATEDIFf(admitbefore, bornmar1, "years"). COMPUTE age_datediffonafter = DATEDIFf(admitonafter, bornmar1, "years"). do if age_datediffbefore ne 0 or age_datediffonafter ne 1. print / year age_datediffbefore age_datediffonafter. end if. end case. end loop. end file. end input program. execute. Art Kendall Social Research ConsultantsOn 12/8/2012 8:39 AM, Art Kendall wrote:
===================== To manage your subscription to SPSSX-L, send a message to [hidden email] (not to SPSSX-L), with no body text except the command. To leave the list, send the command SIGNOFF SPSSX-L For a list of commands to manage subscriptions, send the command INFO REFCARD
Art Kendall
Social Research Consultants |
Administrator
|
In reply to this post by Salbod
I tried to come up with something clever... Coulda Read Art's Post ;-)) --
Please reply to the list and not to my personal email.
Those desiring my consulting or training services please feel free to email me. --- "Nolite dare sanctum canibus neque mittatis margaritas vestras ante porcos ne forte conculcent eas pedibus suis." Cum es damnatorum possederunt porcos iens ut salire off sanguinum cliff in abyssum?" |
In reply to this post by Marta Garcia-Granero
Not sure whether this is what you wanted, but it is old and I believe by RRistow.
/* Calculate age (in years and fraction of years) on June 30,2000.*/ COMPUTE age=CTIME.DAYS(DATE.DMY(30,6,2000)-dob)/365.25. EXECUTE. Data were in the following format: 1940-10-09 2000-10-09 1980-01-07 2000-10-10 1952-10-01 2000-10-09 1980-01-07 2000-10-10 Or alternatively: COMPUTE Age=DATEDIFF($TIME, BirthDate, 'years'). (not sure who the author was on this one! Sorry!) Hope it helps. Mike -----Original Message----- From: SPSSX(r) Discussion [mailto:[hidden email]] On Behalf Of Marta García-Granero Sent: Wednesday, December 05, 2012 9:59 AM To: [hidden email] Subject: Old code to compute age from dates (was it Art Kendall's?) Hi: This is the Stata User Formerly Known As an SPSS Macro Programmer (SUFKASP). Since SPSS 13 I use(d) DATEDIF to compute age from two dates. Stata users seem to keep on using the old formula: int(StudyDate-DateOfBirth)/365.25 (since Stata stores dates as days, it is easier than the SPSS counterpart, that required CTIME.DAYS to convert seconds to days). I recall that years ago we had an interesting thread concerning the errors this method could cause in some cases. I had and slightly improved version: INT(CTIME.DAYS(1+StudyDate-DateOfBirth)/365.25) That avoided some errors, but not all of them. There was a short syntax that computed ages correctly before SPSS 13. It looks that I did not keep a copy of it (bad idea..) because of DATEDIF. I would like to have it again to translate it to a Stata do file. Does anybody keep it yet? Thanks in advance Marta GG (SUFKASP) ===================== To manage your subscription to SPSSX-L, send a message to [hidden email] (not to SPSSX-L), with no body text except the command. To leave the list, send the command SIGNOFF SPSSX-L For a list of commands to manage subscriptions, send the command INFO REFCARD ===================== To manage your subscription to SPSSX-L, send a message to [hidden email] (not to SPSSX-L), with no body text except the command. To leave the list, send the command SIGNOFF SPSSX-L For a list of commands to manage subscriptions, send the command INFO REFCARD |
Administrator
|
Michael, you must have missed Richard's post earlier in this thread where he gave this method:
COMPUTE AgeYears = XDATE.YEAR(StudyDate)-XDATE.YEAR(DateOfBirth). DO IF XDATE.MONTH(StudyDate) LT XDATE.MONTH(DateOfBirth). . COMPUTE AgeYears = AgeYears - 1. ELSE IF XDATE.MONTH(StudyDate) EQ XDATE.MONTH(DateOfBirth). . IF XDATE.MDAY(StudyDate) LT XDATE.MDAY(DateOfBirth) AgeYears = AgeYears - 1. END IF. There were several other posts after that. You can see the entire thread here: http://spssx-discussion.1045642.n5.nabble.com/Old-code-to-compute-age-from-dates-was-it-Art-Kendall-s-td5716678.html Notice Adrian's point about dividing by 365.2425 rather than 365.25 (if one is taking that approach): (1) the correct number of days in the average year, to account for leap years, is 365.2425, not 365.25. There are in fact fewer than one leap year every four years, because there are exceptions applied to century years such as 2000. Using 365.25 for the number of days in a year is the system used in the superseded Julian calendar, whereas the Gregorian calendar we now use employs 365.2425. HTH.
--
Bruce Weaver bweaver@lakeheadu.ca http://sites.google.com/a/lakeheadu.ca/bweaver/ "When all else fails, RTFM." PLEASE NOTE THE FOLLOWING: 1. My Hotmail account is not monitored regularly. To send me an e-mail, please use the address shown above. 2. The SPSSX Discussion forum on Nabble is no longer linked to the SPSSX-L listserv administered by UGA (https://listserv.uga.edu/). |
Free forum by Nabble | Edit this page |