[Tex/LaTex] How to calculate age on a particular date in Years, months, days format

calculations

Lets say my D.O.B is 10/02/1989 and i want to calculate my age on 1st May, 2017, then 28 years, 2 months, and 21 days will be my age on this particular date,
How to get in this format 28 years, 2 months, and 21 days? My D.O.B input will be in this format DD/MM/YYYY.

Best Answer

I took percusse's idea and jumped down the rabbit hole, sort of. However, it certainly doesn't account for any Gregorian/Julian manipulations and, most importantly, it will print an asterisk following the day, when it must assume there are 30 days in the month.

But let's face it, the format of years, months, and days is intrinsically ambiguous. One can certainly tell me how many days it is from 24 April to 23 May, but I argue you cannot tell me how many months and days it is from 24 March to 23 May. It depends on whether I am counting the month as 24 Mar to 24 April and then count the leftover days versus counting the month as 23 April to 23 May and then count the leftover days.

\documentclass{article}
\usepackage{listofitems}
\newcommand\getage[1]{%
  \setsepchar[,]{/}%
  \readlist\starting{#1}%
  \edef\agedays{\the\numexpr\the\day-\starting[1]\relax}%
  \edef\agemonths{\the\numexpr\the\month-\starting[2]\relax}%
  \edef\ageyears{\the\numexpr\the\year-\starting[3]\relax}%
  \ifnum\agedays<0\relax
    \edef\agemonths{\the\numexpr\agemonths-1\relax}%
    \edef\agedays{\the\numexpr\agedays+30\relax*}%
  \fi
  \ifnum\agemonths<0\relax
    \edef\ageyears{\the\numexpr\ageyears-1\relax}%
    \edef\agemonths{\the\numexpr\agemonths+12\relax}%
  \fi
  From #1 to \the\day/\the\month/\the\year{} is
  \ageyears{} years, \agemonths{} months, and \agedays{} days.%
}

\begin{document}
\getage{10/02/1989}

\getage{10/07/1989}

\getage{23/07/1989}

\getage{24/07/1989}
\end{document}

enter image description here

Here, I go a step further and calculate days, assuming I count days from the most recent month before the end date. Note that this is, if you will, defining how months + days are counted. So it avoids ambiguity only by definition. And it still does not account for leap years, and so any calculation that ends in March of a leap year for which the starting \day exceeds the ending \day will be off by 1 day. EDITED to flag calculations with a trailing \dag which may be subject to the leap year error.

REEDITED to allow ending date to be supplied as optional argument (default \today).

\documentclass{article}
\usepackage{listofitems}
\newcommand\getage[2][\relax]{\bgroup%
  \setsepchar[,]{/}%
  \ifx\relax#1\relax\else
    \readlist\ending{#1}%
    \day=\ending[1]\relax%
    \month=\ending[2]\relax%
    \year=\ending[3]\relax%
  \fi%
  \readlist\starting{#2}%
  \xdef\agedays{\the\numexpr\the\day-\starting[1]\relax}%
  \xdef\agemonths{\the\numexpr\the\month-\starting[2]\relax}%
  \xdef\ageyears{\the\numexpr\the\year-\starting[3]\relax}%
  \ifnum\agedays<0\relax
    \monthlength{\the\month}%
    \xdef\agemonths{\the\numexpr\agemonths-1\relax}%
    \xdef\agedays{\the\numexpr\agedays+\themonthlength\relax}%
  \fi
  \ifnum\agemonths<0\relax
    \xdef\ageyears{\the\numexpr\ageyears-1\relax}%
    \xdef\agemonths{\the\numexpr\agemonths+12\relax}%
  \fi
  From #2 to \the\day/\the\month/\the\year{} is
  \ageyears{} years, \agemonths{} months, and \agedays{} days%
  \ifnum\month=3\relax\ifnum\starting[1]>\day\relax$^{\dag}$\fi\fi.%
\egroup}
\newcommand\monthlength[1]{%
  \edef\themonthlength{%
% PRIOR MONTH:    DEC  JAN  FEB  MAR  APR  MAY  JUN  JUL  AUG  SEP  OCT  NOV  
    \ifcase#1 xx\or31\or31\or28\or31\or30\or31\or30\or31\or31\or30\or31\or30\fi%
  }%
}
\begin{document}
\getage{10/02/1989}\par
\getage{10/07/1989}\par
\getage{23/07/1989}\par
\getage{24/07/1989}\par
\getage{24/04/2017}\par
\getage{24/03/2017}\par
\getage[23/3/2017]{24/02/2017}\par
\getage[23/11/2017]{24/10/2017}\par
\getage[01/05/2017]{10/02/1989}
\end{document}

enter image description here

Related Question