Учитывая DateTime
, представляющий день рождения человека, как вычислить его возраст в годах?
Понятное и простое решение.
// Save today's date.
var today = DateTime.Today;
// Calculate the age.
var age = today.Year - birthdate.Year;
// Go back to the year the person was born in case of a leap year
if (birthdate.Date > today.AddYears(-age)) age--;
Однако это предполагает, что вы ищете западное представление о возрасте, а не используете восточноазиатское летоисчисление.
Это странный способ сделать это, но если вы отформатируете дату в yyyymmdd
и вычтете дату рождения из текущей даты, затем отбросите последние 4 цифры, вы получите возраст :)
Я не знаю C#, но думаю, что это будет работать в любом языке.
20080814 - 19800703 = 280111
Отбросить последние 4 цифры = 28
.
Код на C#:
int now = int.Parse(DateTime.Now.ToString("yyyyMMdd"));
int dob = int.Parse(dateOfBirth.ToString("yyyyMMdd"));
int age = (now - dob) / 10000;
Или, как вариант, без приведения типов в виде метода расширения. Проверка ошибок опущена:
public static Int32 GetAge(this DateTime dateOfBirth)
{
var today = DateTime.Today;
var a = (today.Year * 100 + today.Month) * 100 + today.Day;
var b = (dateOfBirth.Year * 100 + dateOfBirth.Month) * 100 + dateOfBirth.Day;
return (a - b) / 10000;
}
Я не знаю, как может быть принято неправильное решение. Правильный сниппет на C# был написан Майклом Штумом.
Вот тестовый фрагмент:
DateTime bDay = new DateTime(2000, 2, 29);
DateTime now = new DateTime(2009, 2, 28);
MessageBox.Show(string.Format("Test {0} {1} {2}",
CalculateAgeWrong1(bDay, now), // outputs 9
CalculateAgeWrong2(bDay, now), // outputs 9
CalculateAgeCorrect(bDay, now), // outputs 8
CalculateAgeCorrect2(bDay, now))); // outputs 8
Здесь есть методы:
public int CalculateAgeWrong1(DateTime birthDate, DateTime now)
{
return new DateTime(now.Subtract(birthDate).Ticks).Year - 1;
}
public int CalculateAgeWrong2(DateTime birthDate, DateTime now)
{
int age = now.Year - birthDate.Year;
if (now < birthDate.AddYears(age))
age--;
return age;
}
public int CalculateAgeCorrect(DateTime birthDate, DateTime now)
{
int age = now.Year - birthDate.Year;
if (now.Month < birthDate.Month || (now.Month == birthDate.Month && now.Day < birthDate.Day))
age--;
return age;
}
public int CalculateAgeCorrect2(DateTime birthDate, DateTime now)
{
int age = now.Year - birthDate.Year;
// for leap years we need this
if (birthDate > now.AddYears(-age)) age--;
// don't use:
// if (birthDate.AddYears(age) > now) age--;
return age;
}
Я не'т думаю, что любой из ответов до сих пор предоставить для культур, которые вычисляют возраст по-разному. См., например, Восточной Азии возраст расплаты против что на Западе.
Какие реальные ответ должен включать локализации. Шаблоне стратегия, вероятно, будет в порядке в этом примере.
Простым ответом на этот вопрос является применение AddYears
, как показано ниже, поскольку это единственный собственный метод, позволяющий прибавить годы к 29-му февраля високосного года и получить правильный результат 28-го февраля для обычных лет.
Некоторые считают, что 1 марта является днем рождения високосных годов, но ни .Net, ни какие-либо официальные правила не поддерживают этого, равно как и обычная логика не объясняет, почему некоторые люди, родившиеся в феврале, должны иметь 75% своих дней рождения в другом месяце.
Далее, метод Age может быть добавлен в качестве расширения к DateTime
. С его помощью вы можете получить возраст самым простым способом:
int age = birthDate.Age();.
public static class DateTimeExtensions
{
/// <summary>
/// Calculates the age in years of the current System.DateTime object today.
/// </summary>
/// <param name="birthDate">The date of birth</param>
/// <returns>Age in years today. 0 is returned for a future date of birth.</returns>
public static int Age(this DateTime birthDate)
{
return Age(birthDate, DateTime.Today);
}
/// <summary>
/// Calculates the age in years of the current System.DateTime object on a later date.
/// </summary>
/// <param name="birthDate">The date of birth</param>
/// <param name="laterDate">The date on which to calculate the age.</param>
/// <returns>Age in years on a later day. 0 is returned as minimum.</returns>
public static int Age(this DateTime birthDate, DateTime laterDate)
{
int age;
age = laterDate.Year - birthDate.Year;
if (age > 0)
{
age -= Convert.ToInt32(laterDate.Date < birthDate.Date.AddYears(age));
}
else
{
age = 0;
}
return age;
}
}
Теперь выполните этот тест:
class Program
{
static void Main(string[] args)
{
RunTest();
}
private static void RunTest()
{
DateTime birthDate = new DateTime(2000, 2, 28);
DateTime laterDate = new DateTime(2011, 2, 27);
string iso = "yyyy-MM-dd";
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
Console.WriteLine("Birth date: " + birthDate.AddDays(i).ToString(iso) + " Later date: " + laterDate.AddDays(j).ToString(iso) + " Age: " + birthDate.AddDays(i).Age(laterDate.AddDays(j)).ToString());
}
}
Console.ReadKey();
}
}
Пример критической даты выглядит следующим образом:
Дата рождения: 2000-02-29 Поздняя дата: 2011-02-28 Возраст: 11.
Вывод:
{
Birth date: 2000-02-28 Later date: 2011-02-27 Age: 10
Birth date: 2000-02-28 Later date: 2011-02-28 Age: 11
Birth date: 2000-02-28 Later date: 2011-03-01 Age: 11
Birth date: 2000-02-29 Later date: 2011-02-27 Age: 10
Birth date: 2000-02-29 Later date: 2011-02-28 Age: 11
Birth date: 2000-02-29 Later date: 2011-03-01 Age: 11
Birth date: 2000-03-01 Later date: 2011-02-27 Age: 10
Birth date: 2000-03-01 Later date: 2011-02-28 Age: 10
Birth date: 2000-03-01 Later date: 2011-03-01 Age: 11
}
И для более поздней даты 2012-02-28:
{
Birth date: 2000-02-28 Later date: 2012-02-28 Age: 12
Birth date: 2000-02-28 Later date: 2012-02-29 Age: 12
Birth date: 2000-02-28 Later date: 2012-03-01 Age: 12
Birth date: 2000-02-29 Later date: 2012-02-28 Age: 11
Birth date: 2000-02-29 Later date: 2012-02-29 Age: 12
Birth date: 2000-02-29 Later date: 2012-03-01 Age: 12
Birth date: 2000-03-01 Later date: 2012-02-28 Age: 11
Birth date: 2000-03-01 Later date: 2012-02-29 Age: 11
Birth date: 2000-03-01 Later date: 2012-03-01 Age: 12
}
Мое предложение
int age = (int) ((DateTime.Now - bday).TotalDays/365.242199);
Что, кажется, год меняется на правильную дату. (Я месте протестировано до возраста 107)
Еще одна функция, не моя, но найденная в Интернете и немного усовершенствованная:
public static int GetAge(DateTime birthDate)
{
DateTime n = DateTime.Now; // To avoid a race condition around midnight
int age = n.Year - birthDate.Year;
if (n.Month < birthDate.Month || (n.Month == birthDate.Month && n.Day < birthDate.Day))
age--;
return age;
}
Только две вещи, которые приходят мне в голову: Как насчет людей из стран, которые не используют григорианский календарь? DateTime.Now находится в культуре, специфичной для сервера, я думаю. У меня нет абсолютно никаких знаний о работе с азиатскими календарями, и я не знаю, есть ли простой способ конвертации дат между календарями, но на всякий случай, если вы'задаетесь вопросом о тех китайских парнях из 4660 года :-)
2 основные проблемы для решения:
1. Рассчитайте точный возраст - в годах, месяцах, днях и т. д.
2. Расчета, как правило, воспринимается возраст - люди, как правило, не волнует, сколько лет у них точно есть, они просто заботятся, когда их день рождения в текущем году.
Решение для 1 очевидно:
DateTime birth = DateTime.Parse("1.1.2000");
DateTime today = DateTime.Today; //we usually don't care about birth time
TimeSpan age = today - birth; //.NET FCL should guarantee this as precise
double ageInDays = age.TotalDays; //total number of days ... also precise
double daysInYear = 365.2425; //statistical value for 400 years
double ageInYears = ageInDays / daysInYear; //can be shifted ... not so precise
Решение для 2 это не так точны в определении общий возраст, но воспринимается как точные люди. Люди часто используют его, когда они вычисляют их возраст и"вручную" и:
DateTime birth = DateTime.Parse("1.1.2000");
DateTime today = DateTime.Today;
int age = today.Year - birth.Year; //people perceive their age in years
if (today.Month < birth.Month ||
((today.Month == birth.Month) && (today.Day < birth.Day)))
{
age--; //birthday in current year not yet reached, we are 1 year younger ;)
//+ no birthday for 29.2. guys ... sorry, just wrong date for birth
}
Примечания к 2.:
Просто еще одно замечание ... я бы создал 2 статических перегруженных методов для него, один для универсального использования, второй для использования удобство:
public static int GetAge(DateTime bithDay, DateTime today)
{
//chosen solution method body
}
public static int GetAge(DateTime birthDay)
{
return GetAge(birthDay, DateTime.Now);
}
Я опоздал на вечеринку, но здесь'ы один-лайнер:
int age = new DateTime(DateTime.Now.Subtract(birthday).Ticks).Year-1;
Это версия, мы используем здесь. Это работает, и это'ы довольно проста. Это'с такой же идеей, как Джефф's, но я думаю, что это's немного понятнее, потому что он отделяет логику вычитания, поэтому он's немного легче понять.
public static int GetAge(this DateTime dateOfBirth, DateTime dateAsAt)
{
return dateAsAt.Year - dateOfBirth.Year - (dateOfBirth.DayOfYear < dateAsAt.DayOfYear ? 0 : 1);
}
Вы могли бы расширить тернарного оператора, чтобы сделать его еще более четким, если вы считаете, что то, что непонятно.
Очевидно, это сделано как метод расширения Датавремя
, но очевидно, что вы можете захватить, что одна строка кода, которая делает работу и поместить его в любом месте. Здесь мы имеем другую перегрузку метода расширения, который проходит в `Датавремя.Теперь, просто для полноты.
Лучший способ, который я знаю из-за високосного года и всего остального:
DateTime birthDate = new DateTime(2000,3,1);
int age = (int)Math.Floor((DateTime.Now - birthDate).TotalDays / 365.25D);
Надеюсь, это поможет.
Я использую этот:
public static class DateTimeExtensions
{
public static int Age(this DateTime birthDate)
{
return Age(birthDate, DateTime.Now);
}
public static int Age(this DateTime birthDate, DateTime offsetDate)
{
int result=0;
result = offsetDate.Year - birthDate.Year;
if (offsetDate.DayOfYear < birthDate.DayOfYear)
{
result--;
}
return result;
}
}
Это дает мне "поподробнее" на этот вопрос. Может быть, это то, что вы'вновь ищу
DateTime birth = new DateTime(1974, 8, 29);
DateTime today = DateTime.Now;
TimeSpan span = today - birth;
DateTime age = DateTime.MinValue + span;
// Make adjustment due to MinValue equalling 1/1/1
int years = age.Year - 1;
int months = age.Month - 1;
int days = age.Day - 1;
// Print out not only how many years old they are but give months and days as well
Console.Write("{0} years, {1} months, {2} days", years, months, days);
Я создал пользователя SQL-сервера функция, определяемая для расчета кто-то's возраст, учитывая их дату рождения. Это полезно, когда вам нужно его как часть запроса:
using System;
using System.Data;
using System.Data.Sql;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
public partial class UserDefinedFunctions
{
[SqlFunction(DataAccess = DataAccessKind.Read)]
public static SqlInt32 CalculateAge(string strBirthDate)
{
DateTime dtBirthDate = new DateTime();
dtBirthDate = Convert.ToDateTime(strBirthDate);
DateTime dtToday = DateTime.Now;
// get the difference in years
int years = dtToday.Year - dtBirthDate.Year;
// subtract another year if we're before the
// birth day in the current year
if (dtToday.Month < dtBirthDate.Month || (dtToday.Month == dtBirthDate.Month && dtToday.Day < dtBirthDate.Day))
years=years-1;
int intCustomerAge = years;
return intCustomerAge;
}
};
Здесь'ы еще один ответ:
public static int AgeInYears(DateTime birthday, DateTime today)
{
return ((today.Year - birthday.Year) * 372 + (today.Month - birthday.Month) * 31 + (today.Day - birthday.Day)) / 372;
}
Это была широкая тестирования. Это выглядит немного как "Магия и". Номер 372-это количество дней будет в год, если каждый месяц имеет 31 день.
Объяснение, почему это работает (поднял здесь) является:
давайте's набор `уя = Датавремя.Сейчас.Год, ИБ = день рождения.Года, МН = Датавремя.Сейчас.Месяц, Мб = день рождения.Месяц, Ду = Датавремя.Сейчас.День, ДБ = день рождения.День
возраст = уя - ИБ + (31*(МН - МВ) + (дн - дБ)) / 372
мы знаем, что нам нужно либо
йн-Ыб
если дата уже достигнута,уя-ИБ-1
, если он не имеет.
а) если в
< млн;Мб
, то есть-341 <= 31*(МН-МВ) <= -31 до -30 <= дн-дБ: <= 30
-371 <= 31*(МН - МВ) + (дн - дБ) <= -1
с целочисленным делением
(31*(МН - МВ) + (дн - дБ)) / 372 = -1
Б) если МН=Мб " и " Ду<дБ
, то есть
31*(МН - МВ) = 0 и -30 <= дн-дБ: <= -1`
с целочисленным делением, снова
(31*(МН - МВ) + (дн - дБ)) / 372 = -1
C) если МН>Мб
, то есть
31 <= 31*(МН-МВ) <= 341 и -30 <= дн-дБ: <= 30`
1 <= 31*(МН - МВ) + (дн - дБ) <= 371
с целочисленным делением
(31*(МН - МВ) + (дн - дБ)) / 372 = 0
д) Если МН=Мб " и " Ду>дБ
, то есть
31*(МН - МВ) = 0 и 1 <= дн-дБ: <= 3`0
с целочисленным делением, снова
(31*(МН - МВ) + (дн - дБ)) / 372 = 0
е) если МН=Мб и Д=дБ
, то есть
31*(МН - МВ) + дн-дБ = 0`
> и, следовательно, (31*(МН - МВ) + (дн - дБ)) / 372 = 0
Я'вэ провел некоторое время, работая над этим и придумал это, чтобы вычислить кого-то's возраст в годах, месяцах и днях. Я'вэ проверку в отношении 29-й проблемы и високосный год февраля и это, кажется, работает, я'd не ценим любую обратную связь:
public void LoopAge(DateTime myDOB, DateTime FutureDate)
{
int years = 0;
int months = 0;
int days = 0;
DateTime tmpMyDOB = new DateTime(myDOB.Year, myDOB.Month, 1);
DateTime tmpFutureDate = new DateTime(FutureDate.Year, FutureDate.Month, 1);
while (tmpMyDOB.AddYears(years).AddMonths(months) < tmpFutureDate)
{
months++;
if (months > 12)
{
years++;
months = months - 12;
}
}
if (FutureDate.Day >= myDOB.Day)
{
days = days + FutureDate.Day - myDOB.Day;
}
else
{
months--;
if (months < 0)
{
years--;
months = months + 12;
}
days +=
DateTime.DaysInMonth(
FutureDate.AddMonths(-1).Year, FutureDate.AddMonths(-1).Month
) + FutureDate.Day - myDOB.Day;
}
//add an extra day if the dob is a leap day
if (DateTime.IsLeapYear(myDOB.Year) && myDOB.Month == 2 && myDOB.Day == 29)
{
//but only if the future date is less than 1st March
if (FutureDate >= new DateTime(FutureDate.Year, 3, 1))
days++;
}
}
Мы должны рассматривать людей, которые меньше, чем 1 год? в качестве китайская культура, мы описываем маленькие дети' возрасте 2 месяца или 4 недели.
Ниже моя реализация, это не так просто, как я себе представляла, особенно для борьбы с датой, как 2/28.
public static string HowOld(DateTime birthday, DateTime now)
{
if (now < birthday)
throw new ArgumentOutOfRangeException("birthday must be less than now.");
TimeSpan diff = now - birthday;
int diffDays = (int)diff.TotalDays;
if (diffDays > 7)//year, month and week
{
int age = now.Year - birthday.Year;
if (birthday > now.AddYears(-age))
age--;
if (age > 0)
{
return age + (age > 1 ? " years" : " year");
}
else
{// month and week
DateTime d = birthday;
int diffMonth = 1;
while (d.AddMonths(diffMonth) <= now)
{
diffMonth++;
}
age = diffMonth-1;
if (age == 1 && d.Day > now.Day)
age--;
if (age > 0)
{
return age + (age > 1 ? " months" : " month");
}
else
{
age = diffDays / 7;
return age + (age > 1 ? " weeks" : " week");
}
}
}
else if (diffDays > 0)
{
int age = diffDays;
return age + (age > 1 ? " days" : " day");
}
else
{
int age = diffDays;
return "just born";
}
}
Эта реализация прошла ниже тестов.
[TestMethod]
public void TestAge()
{
string age = HowOld(new DateTime(2011, 1, 1), new DateTime(2012, 11, 30));
Assert.AreEqual("1 year", age);
age = HowOld(new DateTime(2011, 11, 30), new DateTime(2012, 11, 30));
Assert.AreEqual("1 year", age);
age = HowOld(new DateTime(2001, 1, 1), new DateTime(2012, 11, 30));
Assert.AreEqual("11 years", age);
age = HowOld(new DateTime(2012, 1, 1), new DateTime(2012, 11, 30));
Assert.AreEqual("10 months", age);
age = HowOld(new DateTime(2011, 12, 1), new DateTime(2012, 11, 30));
Assert.AreEqual("11 months", age);
age = HowOld(new DateTime(2012, 10, 1), new DateTime(2012, 11, 30));
Assert.AreEqual("1 month", age);
age = HowOld(new DateTime(2008, 2, 28), new DateTime(2009, 2, 28));
Assert.AreEqual("1 year", age);
age = HowOld(new DateTime(2008, 3, 28), new DateTime(2009, 2, 28));
Assert.AreEqual("11 months", age);
age = HowOld(new DateTime(2008, 3, 28), new DateTime(2009, 3, 28));
Assert.AreEqual("1 year", age);
age = HowOld(new DateTime(2009, 1, 28), new DateTime(2009, 2, 28));
Assert.AreEqual("1 month", age);
age = HowOld(new DateTime(2009, 2, 1), new DateTime(2009, 3, 1));
Assert.AreEqual("1 month", age);
// NOTE.
// new DateTime(2008, 1, 31).AddMonths(1) == new DateTime(2009, 2, 28);
// new DateTime(2008, 1, 28).AddMonths(1) == new DateTime(2009, 2, 28);
age = HowOld(new DateTime(2009, 1, 31), new DateTime(2009, 2, 28));
Assert.AreEqual("4 weeks", age);
age = HowOld(new DateTime(2009, 2, 1), new DateTime(2009, 2, 28));
Assert.AreEqual("3 weeks", age);
age = HowOld(new DateTime(2009, 2, 1), new DateTime(2009, 3, 1));
Assert.AreEqual("1 month", age);
age = HowOld(new DateTime(2012, 11, 5), new DateTime(2012, 11, 30));
Assert.AreEqual("3 weeks", age);
age = HowOld(new DateTime(2012, 11, 1), new DateTime(2012, 11, 30));
Assert.AreEqual("4 weeks", age);
age = HowOld(new DateTime(2012, 11, 20), new DateTime(2012, 11, 30));
Assert.AreEqual("1 week", age);
age = HowOld(new DateTime(2012, 11, 25), new DateTime(2012, 11, 30));
Assert.AreEqual("5 days", age);
age = HowOld(new DateTime(2012, 11, 29), new DateTime(2012, 11, 30));
Assert.AreEqual("1 day", age);
age = HowOld(new DateTime(2012, 11, 30), new DateTime(2012, 11, 30));
Assert.AreEqual("just born", age);
age = HowOld(new DateTime(2000, 2, 29), new DateTime(2009, 2, 28));
Assert.AreEqual("8 years", age);
age = HowOld(new DateTime(2000, 2, 29), new DateTime(2009, 3, 1));
Assert.AreEqual("9 years", age);
Exception e = null;
try
{
age = HowOld(new DateTime(2012, 12, 1), new DateTime(2012, 11, 30));
}
catch (ArgumentOutOfRangeException ex)
{
e = ex;
}
Assert.IsTrue(e != null);
}
Надеюсь, что это's полезн.
Держать его простым (и, возможно, глупый:)).
DateTime birth = new DateTime(1975, 09, 27, 01, 00, 00, 00);
TimeSpan ts = DateTime.Now - birth;
Console.WriteLine("You are approximately " + ts.TotalSeconds.ToString() + " seconds old.");
TimeSpan diff = DateTime.Now - birthdayDateTime;
string age = String.Format("{0:%y} years, {0:%M} months, {0:%d}, days old", diff);
Я'м не знаете, как точно вы'd, как он вернулся к вам, поэтому я просто сделал читаемую строку.
Самый простой способ я'ве когда-либо найденных это. Он работает правильно для США и Западной Европы районов. Может'т поговорить с других районов, особенно в таких местах, как Китай. 4 дополнительных сравнивает, в крайнем случае, после первоначального расчета возраст.
public int AgeInYears(DateTime birthDate, DateTime referenceDate)
{
Debug.Assert(referenceDate >= birthDate,
"birth date must be on or prior to the reference date");
DateTime birth = birthDate.Date;
DateTime reference = referenceDate.Date;
int years = (reference.Year - birth.Year);
//
// an offset of -1 is applied if the birth date has
// not yet occurred in the current year.
//
if (reference.Month > birth.Month);
else if (reference.Month < birth.Month)
--years;
else // in birth month
{
if (reference.Day < birth.Day)
--years;
}
return years ;
}
Я искал ответы на этот и заметил, что никто не сослался на нормативно-правовые последствия високосного дня рождения. Например, в Википедии, Если вы'заново родился 29 февраля в различных юрисдикциях, вы'вновь невисокосный год рождения варьируется:
И насколько я могу судить, в США, законы молчат по этому вопросу, оставив его на общем праве и на то, как различные регулирующие органы определяют в их правилах.
С этой целью улучшение:
public enum LeapDayRule
{
OrdinalDay = 1 ,
LastDayOfMonth = 2 ,
}
static int ComputeAgeInYears(DateTime birth, DateTime reference, LeapYearBirthdayRule ruleInEffect)
{
bool isLeapYearBirthday = CultureInfo.CurrentCulture.Calendar.IsLeapDay(birth.Year, birth.Month, birth.Day);
DateTime cutoff;
if (isLeapYearBirthday && !DateTime.IsLeapYear(reference.Year))
{
switch (ruleInEffect)
{
case LeapDayRule.OrdinalDay:
cutoff = new DateTime(reference.Year, 1, 1)
.AddDays(birth.DayOfYear - 1);
break;
case LeapDayRule.LastDayOfMonth:
cutoff = new DateTime(reference.Year, birth.Month, 1)
.AddMonths(1)
.AddDays(-1);
break;
default:
throw new InvalidOperationException();
}
}
else
{
cutoff = new DateTime(reference.Year, birth.Month, birth.Day);
}
int age = (reference.Year - birth.Year) + (reference >= cutoff ? 0 : -1);
return age < 0 ? 0 : age;
}
Следует отметить, что в этом коде предполагается: