Here's one way, that computes the age the way a normal human being in a western culture would do it for CE dates. Different cultures and calendards reckon age in different ways. For instance, China and other countries in Asia reckon a newborn baby to be 1 year old on the day he is born and his age ticks up on each subsequent Lunar New Year in the Chinese calendar. So if a child was born, say, a month before the Lunar New Year, he would be 1 year old for that month and then would tick up to 2 years old a month after his birth.
This algorithm doesn't work for BCE dates or for dates spanning the transition from the Julian to the Gregorian calendar. That's dicey proposition anyway, no matter how you slice it, since different locations, even within the same country, switched at different times: Russia didn't switch to the Gregorian calendar until after the Bolshevik revolution, for instance).

So Unless you have the locale for the start date and the locale for the end date, you can't accurately compute a time span across the Julian/Gregorian divide.
The algorithm is:
Find the reference date, the most recent monthly birthday on or before the current date.
If the current day-of-the-month is prior to the actual day of birth, use the prior month. If the actual day of birth is later than the last day of the month, cap it at the last day of the month.
For instance, if the current date is 7 March, 2012 and the actual birthday is '31 March, 1990', your reference date is 29 February, 2012.
Compute the difference between your reference date and the date of birth in years and months. This is easy because in the western calendar, years have a consistent number of months. You can use integer division:
int totalMonths = ( 12 * endYear + endMonth ) - ( 12 * startYear + startMonth ) ;
int years = totalMonths / 12 ;
int months = totalMonths % 12 ;
Or you can subtract and carry if necessary.
int years = endYear - startYear ;
int months = endMonth - startMonth ;
if ( months < 0 )
{
months += 12 ;
years -= 1 ;
}
The results should be identical in either case.
The days component is the number of days from the reference date to the current date.
Using this algorithm, one is 0 days old on the day of birth.
Here's my code:
static class HumanAgeFactory
{
public static HumanAge ComputeAge( this DateTime dob )
{
return dob.ComputeAgeAsOf( DateTime.Now ) ;
}
public static HumanAge ComputeAgeAsOf( this DateTime dob , DateTime now )
{
dob = dob.Date ; // toss the time component
now = now.Date ; // toss the time component
if ( dob > now ) throw new ArgumentOutOfRangeException( "dob" , "'now' must be on or after 'dob'" ) ;
DateTime mostRecentBirthDay = MostRecentNthDayOfTheMonthOnOrBefore( dob.Day , now ) ;
int years = mostRecentBirthDay.Year - dob.Year ;
int months = mostRecentBirthDay.Month - dob.Month ;
int days = (int) ( now - mostRecentBirthDay ).TotalDays ;
if ( months < 0 )
{
months += 12 ;
years -= 1 ;
}
if ( days < 0 ) throw new InvalidOperationException() ;
if ( months < 0 ) throw new InvalidOperationException() ;
if ( years < 0 ) throw new InvalidOperationException() ;
HumanAge instance = new HumanAge( years , months , days ) ;
return instance ;
}
private static DateTime MostRecentNthDayOfTheMonthOnOrBefore( int nthDay , DateTime now )
{
if ( nthDay < 1 ) throw new ArgumentOutOfRangeException( "dayOfBirth" ) ;
int year = now.Year ;
int month = now.Month ;
if ( nthDay > now.Day )
{
--month ;
if ( month < 1 )
{
month += 12 ;
year -= 1 ;
}
}
int daysInMonth = CultureInfo.CurrentCulture.Calendar.GetDaysInMonth( year , month ) ;
int day = ( nthDay > daysInMonth ? daysInMonth : nthDay ) ;
DateTime instance = new DateTime( year , month , day ) ;
return instance ;
}
}
public class HumanAge
{
public int Years { get ; private set ; }
public int Months { get ; private set ; }
public int Days { get ; private set ; }
public override string ToString()
{
string instance = string.Format( "{0} {1} , {2} {3} , {4} {5}" ,
Years , Years == 1 ? "year" : "years" ,
Months , Months == 1 ? "month" : "months" ,
Days , Days == 1 ? "day" : "days"
) ;
return instance ;
}
public HumanAge( int years , int months , int days )
{
if ( years < 0 ) throw new ArgumentOutOfRangeException( "years" ) ;
if ( months < 0 || months > 12 ) throw new ArgumentOutOfRangeException( "months" ) ;
if ( days < 0 || days > 31 ) throw new ArgumentOutOfRangeException( "days" ) ;
this.Years = years ;
this.Months = months ;
this.Days = days ;
return ;
}
}