```-------------------------------------------------------------------------------
help for personage
-------------------------------------------------------------------------------

Calculate people's ages or similar daily date differences

personage bdatevar cdatevar [if exp] [in range] , generate(yearsvar
[daysvar [loyvar]])

personage bdatevar [if exp] [in range] , currdate(current_date)
generate(yearsvar [daysvar [loyvar]])

Description

personage is designed in the first instance for calculations of people's
ages from data on their birth date and some "current" daily date.
Depending on what is specified, a new variable is generated containing
age in (completed) years, or the number of anniversaries of that person's
original date of birth; and new variables may be generated containing (1)
time since last birthday in days and (2) length of the current year.

There are two syntaxes. In the first, the user supplies two daily date
variables, the first of which is birth date bdatevar and the second of
which is some "current" date cdatevar. As is usual, such variables may be
genuinely variable, taking on different values in different observations.

In the second syntax, the user supplies a daily date variable, which is
taken to be the birth date bdatevar, and also through the currdate()
option an expression defining the current daily date.

Although calculating ages of people is the motivating problem, nothing
stops application to any problem requiring completed years, and
optionally extra days, as a representation of the difference between two
daily dates (including differences of either positive or negative sign).
Descriptions here implying birth dates and current dates are for
concreteness and do not exclude other applications.

Remarks

Most differences between dates and/or times are just a matter of
subtraction.  Daily date differences have an extra twist because of the
two-fold complications caused by leap years, namely that years may be 365
or 366 days long and that 29 February occurs only in leap years.  In
personage people born on 29 February are deemed to have a virtual
birthday on 28 February in non-leap years. The approximation that years
average 365.25 days is often used in statistical computing, but this
program offers an "exact" calculation.

personage warns if any variable specified has a format that does not

Users wanting a string representation combining years and days can just
concatenate afterwards.

personage deliberately is shy of offering a computed fraction of year for
time since the last birthday (anniversary), leaving it to users to decide
how to define and store such fractions. Note in particular for replicable
results that fractions will differ slightly as between storage in float
and double variables.  If you do not understand this, search precision
for material explaining why.

personage is not suitable for date-times measured in milliseconds. Use
dofc() or dofC() as appropriate first to convert to daily dates.

Options

currdate() provides a specification of the "current" daily date(s) as
numeric value(s) through a defining expression.  Commonly, but not
necessarily, this will be an expression defining a constant such as
"mdy(10, 20, 2012)".  currdate() is required as an option with the
second syntax and not allowed with the first syntax.

generate() specifies one, two or three new variable names.  In the first
case, a new variable is generated containing age as number of
completed years. In the second case, two new variables are generated
containing age as number of completed years and number of days since
last birthday. In the third case, three new variables are generated
containing age as number of completed years, number of days since
last birthday, and length of year so far, or number of days in the
year that ends with the next birthday. This last, which will be 365
or 366, is for users wishing to carry out further calculations, most
simply of fraction of year elapsed since the last birthday.
generate() is a required option.

Examples

. clear
. mat values = (28, 19, 28, 29, 29, 29\3, 11, 2, 2, 2, 2\1952, 1952,
2011, 2012, 2012, 1996)

. 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 -2

. replace cdate = mdy(8, 31, 2013) in L
. format bdate cdate %td
. personage bdate cdate, gen(age1 days1)
. personage bdate, currdate(mdy(12,31,2012)) gen(age2 days2)
. list

Author

Nicholas J. Cox, Durham University, U.K.
n.j.cox@durham.ac.uk

Acknowledgments

A question from José Maria Pacheco de Souza, Universidade de São Paulo,
rekindled my interest in this problem. Phil Clayton, Mike Corbett and
Alison Smith all found embarrassing bugs.

```