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 start with "%d" or "%td".

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.