Вот один способ, который вычисляет возраст так, как нормальный человек в западной культуре сделал бы это для дат CE .Разные культуры и календари считаются возрастом по-разному.Например, Китай и другие страны Азии считают, что новорожденному ребенку будет 1 год в день его рождения, и его возраст отмечается в каждый последующий лунный Новый год по китайскому календарю.Так, если бы ребенок родился, скажем, за месяц до Лунного Нового года, ему бы исполнился 1 год в этом месяце, а затем он отмечал бы до 2 лет через месяц после его рождения.
Этот алгоритм не работаетне работает для дат BCE или для дат, охватывающих переход от юлианского к григорианскому календарю.В любом случае, это рискованное предложение, независимо от того, как вы его нарезаете, поскольку разные места, даже в пределах одной страны, переключались в разное время: Россия не переключалась на григорианский календарь, например, до окончания большевистской революции).

Итак, если у вас нет локали для даты начала и локали для даты окончания, вы не можете точно вычислить промежуток времени через юлианский / григорианский дележ.
Алгоритм:
Найти справочную дату , самый последний месячный день рождения в или до текущей даты.
Если текущий день месяца предшествует фактическому дню рождения, используйте предыдущий месяц.Если фактический день рождения позже, чем последний день месяца, ограничьте его последним днем месяца.
Например, если текущей датой является 7 марта 2012 года, а фактическим днем рождения является '31 марта 1990 г., ваша контрольная дата - 29 февраля 2012 г.
Рассчитайте разницу между вашей контрольной датой и датойрождение в годах и месяцах.Это легко, потому что в западном календаре годы имеют постоянное количество месяцев.Вы можете использовать целочисленное деление:
int totalMonths = (12 * endYear + endMonth) - (12 * startYear + startMonth);int years = totalMonths / 12;int months = totalMonths% 12;
Или вы можете вычитать и переносить при необходимости.
int years = endYear - startYear ;
int months = endMonth - startMonth ;
if ( months < 0 )
{
months += 12 ;
years -= 1 ;
}
Результаты должны быть идентичны в любом случае.
Компонент days - это количество дней от ссылочной даты до текущей даты.
При использовании этого алгоритма один день составляет 0 дней в день рождения.
Вот мой код:
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 ;
}
}