Notice: On April 23, 2014, Statalist moved from an email list to a forum, based at statalist.org.
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: st: how to get age in number of years, months and days
From
Phil Clayton <[email protected]>
To
[email protected]
Subject
Re: st: how to get age in number of years, months and days
Date
Sun, 21 Oct 2012 15:54:11 +1100
I've been playing with something like this (beware wrapped lines):
----------------
clear
input str9 d1 str9 d2
24oct1980 19oct2012
30sep1954 5aug1989
31oct1974 10sep2002
31oct1974 30oct2002
31mar1985 30mar1995
29feb2000 28feb2004
29feb2000 1mar2004
end
gen date1=date(d1, "DMY")
gen date2=date(d2, "DMY")
format %td date1 date2
gen years=floor(((ym(year(date2), month(date2)) - ym(year(date1), month(date1))) - (day(date2) < day(date1))) / 12)
gen months=(ym(year(date2), month(date2)) - ym(year(date1), month(date1))) - (day(date2) < day(date1)) - 12*years
gen days=date2 - (dofm(mofd(date1) + 12*years + months) + day(date1) - 1)
list
----------------
Of course handling leap years and birthdays on 29 Feb is a little arbitrary. The code for calculating age in years is based on Dan Blanchette's code at the end of this page:
http://www.ats.ucla.edu/stat//stata/modules/dates.htm
I think Nick's approach of calculating years and days is probably better. However, Nick's code seems to fail with the second last set of dates above.
Phil
On 20/10/2012, at 9:37 PM, Nick Cox <[email protected]> wrote:
> A better answer would be to do it properly, except that as earlier
> said I suggest that years and days is a better way to go.
>
> Here is some code. It has not been very much tested. It is a bit
> messy, because it needs to be general enough to deal with leap years
> and with persons born on February 29 (two related but not identical
> problems).
>
> Some notes:
>
> 1. -personage- expects input of daily date variables and warns if it
> does not find a format that implies one such.
>
> 2. Although age of person is the motivating problem, nothing stops
> application to any problem requiring years and days as a
> representation of the difference between two daily dates (including
> differences of positive or negative sign).
>
> 3. Users wanting a string representation can just concatenate afterwards.
>
> 4. People born on 29 February are deemed to have a virtual birthday on
> 28 February in non-leap years.
>
> 5. I wondered about using the -doy()- function instead, but a gut
> feeling is that makes the code no easier on balance. I will look at
> that in due course.
>
> 6. Watch out for long lines if tempted to copy this and play with it.
>
> *! 1.0.0 NJC 20 October 2012
> program personage
> version 8.2
> syntax varlist(numeric min=2 max=2) [if] [in] , Generate(str)
>
> tokenize `varlist'
> args bdate cdate
>
> marksample touse
> qui count if `touse'
> if r(N) == 0 error 2000
>
> foreach v in `bdate' `cdate' {
> local fmt : format `v'
> if substr("`fmt'", 1, 2) != "%d" {
> if substr("`fmt'", 1, 3) != "%td" {
> di "warning: `v' not formatted as daily date"
> }
> }
> }
>
> tokenize `generate'
> args yearsvar daysvar garbage
> if "`garbage'" != "" {
> di as err "at most two names should be given in generate()"
> exit 198
> }
> if "`daysvar'" != "" {
> confirm new variable `daysvar'
> }
> confirm new variable `yearsvar'
>
> tempvar work
> local bday_this_cal_yr ///
> (month(`bdate') < month(`cdate')) | (month(`bdate') == month(`cdate')
> & day(`bdate') <= day(`cdate'))
>
> quietly {
> // first focus on calculating last birthday
>
> // 1. last b'day earlier this year if current date is as late or
> later in year
> gen `work' = mdy(month(`bdate'), day(`bdate'), year(`cdate')) if
> `bday_this_cal_yr'
>
> // 2. else it was last year
> replace `work' = mdy(month(`bdate'), day(`bdate'), year(`cdate') -
> 1) if missing(`work')
>
> // but 1. won't work if born Feb 29 and it's not a leap year
> // 2. won't work if born Feb 29 and last year not a leap year
> local born_feb29 month(`bdate') == 2 & day(`bdate') == 29
> local this_not_leap missing(mdy(2, 29, year(`cdate')))
> local last_not_leap missing(mdy(2, 29, year(`cdate') - 1))
>
> // 3. is a fix for problem with 1.
> replace `work' = mdy(2, 28, year(`cdate')) if `this_not_leap' &
> `born_feb29' & `cdate' >= mdy(2, 28, year(`cdate'))
> // 4. is a fix for problem with 2.
> replace `work' = mdy(2, 28, year(`cdate') - 1) if `last_not_leap' &
> `born_feb29' & `cdate' < mdy(2, 28, year(`cdate'))
>
> // now we can calculate results
>
> gen `yearsvar' = year(`work') - year(`bdate') if `touse'
> if "`daysvar'" != "" {
> gen `daysvar' = `cdate' - `work' if `touse'
> }
>
> compress `yearsvar' `daysvar'
> }
> end
>
> Here is a sample test script
>
> clear
>
> mat values = (28, 19, 28, 29, 29\3, 11, 2, 2, 2\1952, 1952, 2011, 2012, 2012)
> set obs `=colsof(values)'
> gen bdate = mdy(values[2, _n], values[1, _n], values[3, _n])
> gen cdate = mdy(10,19,2012)
> replace cdate = mdy(2, 29, 2012) in L
> format bdate cdate %td
>
> personage bdate cdate, gen(age_y age_d)
>
> list
>
>
> On Fri, Oct 19, 2012 at 12:21 AM, Nick Cox <[email protected]> wrote:
>> I am not aware that you are missing something. My guess is that this
>> is too awkward to be usable and too fiddly to be an amusing
>> programming problem.
>>
>> In particular, it doesn't sound an easy thing to work with given that
>> months are of unequal length. Even years and days sounds a little
>> tricky.
>>
>> Most people seem satisfied with the difference in dates divided by
>> 365.25. I've often seen one-liners giving that.
>>
>> To spell out the obvious, you'd need to treat leap years carefully and
>> in particular anyone born on 29 February.
>>
>> There should be a few such people on this list; what do you/they do?
>> Celebrate on 28 Feb or 1 March?
>>
>> There is discussion of leap years at
>>
>> FAQ . . . . . . . . . . . . . . . . . . . . . . . . . Leap year indicators
>> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . N. J. Cox
>> 1/04 How do I identify leap years in Stata?
>> http://www.stata.com/support/faqs/data/leapyear.html
>>
>> Nick
>>
>> On Thu, Oct 18, 2012 at 11:10 PM, jose maria pacheco de souza
>> <[email protected]> wrote:
>>
>>> is there any user writen program that presents the differences between two
>>> dates DMY (today date and birthday date, say) as number of years, months and
>>> days?
>>> I tried the help (all three searchs), the dates and times help and the pdf
>>> manual. Maybe I am missing something.
> *
> * For searches and help try:
> * http://www.stata.com/help.cgi?search
> * http://www.stata.com/support/faqs/resources/statalist-faq/
> * http://www.ats.ucla.edu/stat/stata/
*
* For searches and help try:
* http://www.stata.com/help.cgi?search
* http://www.stata.com/support/faqs/resources/statalist-faq/
* http://www.ats.ucla.edu/stat/stata/