在C#中,如何根据DateTime类型的生日计算某人的年龄?


1865

给定一个DateTime人的生日,我如何计算他们的年龄(以岁为单位)?


147
到目前为止,所有答案都错过了,这取决于人的出生地和现在的位置。
Yaur 2011年

40
@Yaur:只需将现在+出生的时间转换为GMT / UTC,年龄只是一个相对值,因此时区无关紧要。要确定用户的当前时区,可以使用GeoLocating。
Stefan Steiger,

为什么不考虑[Julian Date] [1]?[1]:stackoverflow.com/questions/7103064/...
穆罕默德Hewedy

5
如果我们考虑@Yaur关于跨时区计算的建议,那么夏时制是否应以任何方式影响计算?
DDM

6
不赞成投票,因为这显然是一个家庭作业问题,没有提供任何现有的尝试。
玛丽

Answers:


2121

一个易于理解和简单的解决方案。

// 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--;

但是,这假设您正在寻找西方的年龄观念,而不是使用东亚估算


252
只是想评论DateTime.Now性能。如果不需要准确的时区值,请使用DateTime.UtcNow,它要快得多。
JAG

104
鉴于我们正在谈论生日,您只能使用DateTime.Today鉴于时间部分不相关。
Tristan Warner-Smith,2009年

78
此答案不适用于所有地区和所有年龄段。目前有几个人出生后,有几个国家跳过了约会,包括俄罗斯(1918),希腊(1924)和土耳其(1926)。
拉斯D

30
实际上,它仍然不完全正确。此代码假定“ bday”是DateTime的日期部分。这是一个极端情况(我想大多数人只会传递日期而不是日期时间),但是如果您将生日作为日期和时间传递,而时间大于00:00:00,那么您ll碰到Danvil指出的错误。设置bday = bday.Date可以解决此问题。
岛之风

119
最后一行让我想得太多。相反如何:if(bday.AddYears(age)> now)age--; 这似乎是一种更直观的表达。
cdiggins 2011年

1015

这是一种奇怪的方法,但是如果您将日期格式设置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;
}

5
实际上,这对于在带日期时间字段(自01-011900开始的总天数)的MS-SQL上使用非常有用
Patrik

在您的替代答案中,您可以通过减去年份然后减去month * 30.5 + day并除以366
numerek

5
@numerek请张贴您建议的修改作为自己的答案。就其价值而言,当前年份乘以10000远不及整数溢出(两个数量级)。20,150,000 vs 2,147,483,648
GalacticCowboy

7
@LongChalk 20180101 - 20171231 = 8870。删除最后4位数字,就可以知道0这个年龄。你是怎么得到的1
Rufus L

4
我知道这是一个旧答案,但是我不会从中做出扩展方法,这不是定义此类逻辑的正确位置。
卢卡·费里

391

这是一个测试代码段:

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;
}

33
尽管此代码有效,但它声称在on日出生的人在非March年的3月1日而不是2月28日达到第二年的年龄。实际上,这两种选择都是正确的维基百科对此有话要说。因此,尽管您的代码不是“错误的”,但公认的解决方案也不是。
马特·约翰逊·品脱

18
@MattJohnson我认为这是正确的。如果我的生日是2月29日,那么2月28日我的生日还没有过去,我的年龄应该与2月27日相同。但是,在3月1日,我们的生日已经过去了,我应该是下一个年龄。在美国,一家销售酒精饮料的企业会标有“如果您在YYYY出生后第二天就不能购买酒精饮料”这样的标语(每年YYYY会发生变化)。这意味着,一个人出生于02月29不能买酒年02月28日的一年,他们把21(大部分地方),并赋予的想法,他们不是大了一岁,直到支持3月1日
jfren484

4
@ jfren484-阅读Wikipedia文章。各个司法管辖区的差异很大。
马特·约翰逊

9
@ jfren484您的主张与哲学绝对无关;但是一切都与你自己的个人感觉有关。如果2月29日出生的人“年龄”在很大程度上不重要,除非该年龄形成“法定年龄界限”(例如可以买酒,投票,领取退休金,参军,获得驾驶执照)。考虑美国的饮酒年龄(21岁):对于大多数人来说,是7670天。如果在leap年2月29日之前或leap年3月1日之前出生,则是7671天。如果在2月29日出生:2月28日为7670天,3月1日为7671天。选择是任意的,可以任意选择
幻灭了

4
@CraigYoung您从哲学上不理解我的意思。我用这个词作为法律上的对比。如果要编写的应用程序需要知道某人的法定年龄,那么他们所需要知道的就是如何使用其应用程序的法律管辖权/来对待2月29日出生的人。但是,如果我们谈论应该如何对待,那么从定义上讲就是哲学。是的,我的意见是我自己的意见,但是正如我所说,我认为3月1日的辩论比2月28日的辩论容易
jfren484

109

简单的答案是申请 AddYears如下所示,因为这是唯一将native年2月29日加年并获得普通年2月28日正确结果的本地方法。

有人认为3月1日是跨越式的生日,但是.Net或任何官方规则都没有支持这一点,也没有通用的逻辑解释为什么2月出生的某些人在另一个月应该有其生日的75%。

此外,Age方法适合作为的扩展添加DateTime。这样,您可以以最简单的方式获得年龄:

  1. 项目清单

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
}

4
关于在3月1日拥有2月29日生日的评论,从技术上讲,在28日拥有生日还为时过早(实际上早了1天)。一日是一天,为时已晚。但是由于生日是在两者之间,所以使用1st来计算非ap年的年龄对我来说更有意义,因为该人的确确实是每年3月1日(以及2日和3日)的那个年龄,而不是2月28日。
Cyber​​Claw

1
从软件设计的角度来看,将其编写为扩展方法对我来说没有多大意义。date.Age(other)
marsze

90

我的建议

int age = (int) ((DateTime.Now - bday).TotalDays/365.242199);

似乎在正确的日期更改了年份。(我现场测试到107岁。)


26
我不认为哈里·帕奇会赞赏你的现场测试方法: latimes.com/news/obituaries/...
MusiGenesis

3
谷歌说days in a year = 365.242199
mpen

12
阳历的平均年长为365.2425天。
dan04

4
我想说,这是最简单的解决方案之一,足够好。谁在乎我是否在X生日前半天,并且程序说我X岁。该程序或多或少是正确的,尽管不是数学上的。我真的很喜欢这个解决方案。
PeterPerháč2011年

13
^^因为有时很重要。在我的测试中,这在人们生日那天失败了,它报告了他们比他们还年轻。
乍得2011年

76

另一个功能,不是我自己的,而是在网上找到并进行了一些改进:

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年以来的那些中国人:-)


这似乎可以最好地处理不同的区域(日期格式)。
webdad3 2016年

53

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.的注释:

  • 这是我的首选解决方案
  • 我们不能使用DateTime.DayOfYear或TimeSpans,因为它们会移动years年中的天数
  • 我已经增加了几行以提高可读性

请再注意一点...我将为其创建2个静态重载方法,一种用于通用用法,第二种用于使用友好:

public static int GetAge(DateTime bithDay, DateTime today) 
{ 
  //chosen solution method body
}

public static int GetAge(DateTime birthDay) 
{ 
  return GetAge(birthDay, DateTime.Now);
}

50

这里是单线:

int age = new DateTime(DateTime.Now.Subtract(birthday).Ticks).Year-1;

23
这已破了。可测试:公共静态int CalculateAge(DateTime dateOfBirth,DateTime dateToCalculateAge){返回新的DateTime(dateToCalculateAge.Subtract(dateOfBirth).Ticks).Year-1;} ...当我输入1990-06-01并计算其14岁生日(1990-05-31)当天的年龄时,给出14岁。
肯森2011年

43

这是我们在这里使用的版本。它有效,而且非常简单。这与Jeff的想法相同,但我认为它更清楚一点,因为它分离出了减法逻辑,因此更容易理解。

public static int GetAge(this DateTime dateOfBirth, DateTime dateAsAt)
{
    return dateAsAt.Year - dateOfBirth.Year - (dateOfBirth.DayOfYear < dateAsAt.DayOfYear ? 0 : 1);
}

如果您认为这类事情不清楚,可以扩展三元运算符以使其更加清晰。

显然,这是作为上的扩展方法完成的DateTime,但是显然,您可以抓住完成工作的那一行代码,并将其放在任何地方。在这里DateTime.Now,为了完整性,我们传入了Extension方法的另一个重载。


6
我认为当dateOfBirth或dateAsAt中的一个恰好落入a年时,这一天可能会关闭。考虑一个在2003年3月1日出生的人的年龄,在2004年2月29日出生的人的年龄。要纠正这个问题,您需要对(Month,DayOfMonth)对进行词典词典比较,并将其用于有条件的。
道格·麦克林

1
也不会显示您生日那天的正确年龄。
dotjoe

43

由于leap年和一切,我所知道的最好方法是:

DateTime birthDate = new DateTime(2000,3,1);
int age = (int)Math.Floor((DateTime.Now - birthDate).TotalDays / 365.25D);

34

我用这个:

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;
    }
}

32

这为这个问题提供了“更多细节”。也许这就是您要寻找的

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);

1
这并非一直都有效。将跨度添加到DateTime.MinValue可以正常工作,这不能解决leap年等问题。如果使用AddYears(),AddMonths和AddDays()函数将Age,months和days添加到Age中,它将不会总是返回Datetime现在日期。
Athanasios Kataras

3
时间跨度本身会自动考虑2个日期之间的leap年,因此我不确定您的情况。我曾在Microsoft论坛上问过,Microsoft已经确认它考虑了2个日期之间的leap年。
杰奎琳·洛里奥

2
考虑以下两个参量。1st DateTime.Now现在是2001年1月1日,孩子在2000年1月1日出生。2000年是a年,结果将是1年,0个月零1天。在第二阶段,DateTime.Now现在是2002年1月1日,孩子在2001年1月1日出生。在这种情况下,结果将是1年0个月0天。发生这种情况是因为您要增加非a年的时间跨度。如果DateTime.MinValue是a年,则结果将是第一年为1年,零年为11个月零30天。(在您的代码中尝试)。
Athanasios Kataras

1
赞!我想出了一个几乎相同的解决方案(我使用DateTime.MinValue.AddTicks(span.Ticks)而不是+,但是结果相同,而且您的代码少了几个字符)。
Makotosan

4
你说得对,事实并非如此。但是如果那是结果。为什么这有关系?没有。无论是否有飞跃,都有一些例子无法解决问题。那就是我想展示的。DIFF是正确的。跨度考虑了leap年。但是,添加到基准日期不是。尝试代码中的示例,您会发现我是对的。
Athanasios Kataras

28

我创建了一个SQL Server用户定义函数来计算某人的年龄(给定生日)。当您在查询中需要它时,这将很有用:

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;
    }
};

28

这是另一个答案:

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天,则一年中的天数。

其工作原理的说明(从此处取消)是:

开始吧 Yn = DateTime.Now.Year, Yb = birthday.Year, Mn = DateTime.Now.Month, Mb = birthday.Month, Dn = DateTime.Now.Day, Db = birthday.Day

age = Yn - Yb + (31*(Mn - Mb) + (Dn - Db)) / 372

我们知道,我们需要的是Yn-Yb是否已经达到日期,Yn-Yb-1如果尚未达到。

a)如果Mn<Mb-341 <= 31*(Mn-Mb) <= -31 and -30 <= Dn-Db <= 30

-371 <= 31*(Mn - Mb) + (Dn - Db) <= -1

带整数除法

(31*(Mn - Mb) + (Dn - Db)) / 372 = -1

b)如果Mn=MbDn<Db,我们有31*(Mn - Mb) = 0 and -30 <= Dn-Db <= -1

再用整数除法

(31*(Mn - Mb) + (Dn - Db)) / 372 = -1

c)如果Mn>Mb31 <= 31*(Mn-Mb) <= 341 and -30 <= Dn-Db <= 30

1 <= 31*(Mn - Mb) + (Dn - Db) <= 371

带整数除法

(31*(Mn - Mb) + (Dn - Db)) / 372 = 0

d)如果Mn=MbDn>Db,则为31*(Mn - Mb) = 0 and 1 <= Dn-Db <= 30

再用整数除法

(31*(Mn - Mb) + (Dn - Db)) / 372 = 0

e)如果Mn=MbDn=Db,我们有31*(Mn - Mb) + Dn-Db = 0

因此 (31*(Mn - Mb) + (Dn - Db)) / 372 = 0


3
我偶然发现了这个漫长而烦人的讨论,而您的解决方案是一种非常好的小型方法。感谢您保持简单
-nabuchodonossor

25

我花了一些时间来研究这个问题,并想出了这个数字来计算某人的年,月和日。我已经针对2月29日的问题和leap年进行了测试,它似乎有效,我希望收到任何反馈:

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++;
    }

}

21

我们是否需要考虑小于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);
}

希望对您有所帮助。


20

保持简单(可能很愚蠢:)。

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是我的首选,但发现它不提供TotalYears属性。您可以尝试(ts.TotalDays / 365)-但它不能解决leap年等问题。
Lazlow

19

我发现过的最简单的方法就是这个。它适用于美国和西欧地区。不能和其他地方说话,尤其是像中国这样的地方。最初计算年龄后,最多最多有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 ;
}

我一直在寻找答案,发现没有人提到leap日出生的法规/法律含义。例如,根据Wikipedia,如果您于2月29日出生在各个司法管辖区,则您的非-年生日会有所不同:

  • 在英国和香港:这是一年中的第几天,因此第二天3月1日是您的生日。
  • 在新西兰:前一天是2月28日,用于驾驶员执照发放,3月1日是其他目的。
  • 台湾:2月28日。

据我所知,在美国,成文法对此事保持沉默,这取决于普通法以及各种监管机构如何在其法规中定义事物。

为此,需要改进:

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;
}

应该注意的是,该代码假定:

  • 西方(欧洲)对年龄的估算,以及
  • 日历,如公历,在一个月末插入一个leap日。

19
TimeSpan diff = DateTime.Now - birthdayDateTime;
string age = String.Format("{0:%y} years, {0:%M} months, {0:%d}, days old", diff);

我不确定您希望它返回的准确程度如何,所以我只写了一个可读的字符串。


18

这不是直接的答案,而是更多从准科学的角度对眼前问题的哲学推理。

我会争辩说,这个问题并未指定衡量年龄的单位或文化,大多数答案似乎都假定整数表示年度。时间的SI单位是second,因此,正确的通用答案应该是(当然假设是归一化的DateTime,并且不考虑相对论效应):

var lifeInSeconds = (DateTime.Now.Ticks - then.Ticks)/TickFactor;

用基督教的方式计算年龄(岁):

var then = ... // Then, in this case the birthday
var now = DateTime.UtcNow;
int age = now.Year - then.Year;
if (now.AddYears(-age) < then) age--;

在金融中,计算通常称为“ 天数分数”的东西时也存在类似的问题,也,这在给定时期内大约为数年。年龄问题确实是一个衡量时间的问题。

实际/实际(“正确地”计算所有天数)约定的示例:

DateTime start, end = .... // Whatever, assume start is before end

double startYearContribution = 1 - (double) start.DayOfYear / (double) (DateTime.IsLeapYear(start.Year) ? 366 : 365);
double endYearContribution = (double)end.DayOfYear / (double)(DateTime.IsLeapYear(end.Year) ? 366 : 365);
double middleContribution = (double) (end.Year - start.Year - 1);

double DCF = startYearContribution + endYearContribution + middleContribution;

通常,测量时间的另一种相当普遍的方法是通过“序列化”(命名此日期约定的家伙一定很认真地已经绊倒了):

DateTime start, end = .... // Whatever, assume start is before end
int days = (end - start).Days;

我想知道相对于以相对论为基础的年龄,到目前为止,要比一个人的一生中对太阳周围的太阳周期的粗略估计要走多长时间才有用:)换句话说,当必须给一个时期指定一个位置或一个表示运动的函数以使其本身有效:)


17

这是一个解决方案。

DateTime dateOfBirth = new DateTime(2000, 4, 18);
DateTime currentDate = DateTime.Now;

int ageInYears = 0;
int ageInMonths = 0;
int ageInDays = 0;

ageInDays = currentDate.Day - dateOfBirth.Day;
ageInMonths = currentDate.Month - dateOfBirth.Month;
ageInYears = currentDate.Year - dateOfBirth.Year;

if (ageInDays < 0)
{
    ageInDays += DateTime.DaysInMonth(currentDate.Year, currentDate.Month);
    ageInMonths = ageInMonths--;

    if (ageInMonths < 0)
    {
        ageInMonths += 12;
        ageInYears--;
    }
}

if (ageInMonths < 0)
{
    ageInMonths += 12;
    ageInYears--;
}

Console.WriteLine("{0}, {1}, {2}", ageInYears, ageInMonths, ageInDays);

使用字符串concat,这将是可能的:47 Yrs 11 Mo 7天
JoshYates1980

16

与2月28日的任何一年相比,这是能够解决2月29日生日的最准确答案之一。

public int GetAge(DateTime birthDate)
{
    int age = DateTime.Now.Year - birthDate.Year;

    if (birthDate.DayOfYear > DateTime.Now.DayOfYear)
        age--;

    return age;
}




今天是今天!(下一个是从现在开始的四年。)
Peter Mortensen

15

我有一个自定义的方法来计算年龄,外加奖金验证消息以防万一:

public void GetAge(DateTime dob, DateTime now, out int years, out int months, out int days)
{
    years = 0;
    months = 0;
    days = 0;

    DateTime tmpdob = new DateTime(dob.Year, dob.Month, 1);
    DateTime tmpnow = new DateTime(now.Year, now.Month, 1);

    while (tmpdob.AddYears(years).AddMonths(months) < tmpnow)
    {
        months++;
        if (months > 12)
        {
            years++;
            months = months - 12;
        }
    }

    if (now.Day >= dob.Day)
        days = days + now.Day - dob.Day;
    else
    {
        months--;
        if (months < 0)
        {
            years--;
            months = months + 12;
        }
        days += DateTime.DaysInMonth(now.AddMonths(-1).Year, now.AddMonths(-1).Month) + now.Day - dob.Day;
    }

    if (DateTime.IsLeapYear(dob.Year) && dob.Month == 2 && dob.Day == 29 && now >= new DateTime(now.Year, 3, 1))
        days++;

}   

private string ValidateDate(DateTime dob) //This method will validate the date
{
    int Years = 0; int Months = 0; int Days = 0;

    GetAge(dob, DateTime.Now, out Years, out Months, out Days);

    if (Years < 18)
        message =  Years + " is too young. Please try again on your 18th birthday.";
    else if (Years >= 65)
        message = Years + " is too old. Date of Birth must not be 65 or older.";
    else
        return null; //Denotes validation passed
}

方法在这里调用,并传递出日期时间值(如果服务器设置为美国语言环境,则为MM / dd / yyyy)。将其替换为任何要显示的消息框或容器:

DateTime dob = DateTime.Parse("03/10/1982");  

string message = ValidateDate(dob);

lbldatemessage.Visible = !StringIsNullOrWhitespace(message);
lbldatemessage.Text = message ?? ""; //Ternary if message is null then default to empty string

请记住,您可以按照自己喜欢的方式格式化邮件。


14

这个解决方案怎么样?

static string CalcAge(DateTime birthDay)
{
    DateTime currentDate = DateTime.Now;         
    int approximateAge = currentDate.Year - birthDay.Year;
    int daysToNextBirthDay = (birthDay.Month * 30 + birthDay.Day) - 
        (currentDate.Month * 30 + currentDate.Day) ;

    if (approximateAge == 0 || approximateAge == 1)
    {                
        int month =  Math.Abs(daysToNextBirthDay / 30);
        int days = Math.Abs(daysToNextBirthDay % 30);

        if (month == 0)
            return "Your age is: " + daysToNextBirthDay + " days";

        return "Your age is: " + month + " months and " + days + " days"; ;
    }

    if (daysToNextBirthDay > 0)
        return "Your age is: " + --approximateAge + " Years";

    return "Your age is: " + approximateAge + " Years"; ;
}

12
private int GetAge(int _year, int _month, int _day
{
    DateTime yourBirthDate= new DateTime(_year, _month, _day);

    DateTime todaysDateTime = DateTime.Today;
    int noOfYears = todaysDateTime.Year - yourBirthDate.Year;

    if (DateTime.Now.Month < yourBirthDate.Month ||
        (DateTime.Now.Month == yourBirthDate.Month && DateTime.Now.Day < yourBirthDate.Day))
    {
        noOfYears--;
    }

    return  noOfYears;
}

10

以下方法(摘自Time Period Library中的.NETDateDiff)考虑了区域性信息的日历:

// ----------------------------------------------------------------------
private static int YearDiff( DateTime date1, DateTime date2 )
{
  return YearDiff( date1, date2, DateTimeFormatInfo.CurrentInfo.Calendar );
} // YearDiff

// ----------------------------------------------------------------------
private static int YearDiff( DateTime date1, DateTime date2, Calendar calendar )
{
  if ( date1.Equals( date2 ) )
  {
    return 0;
  }

  int year1 = calendar.GetYear( date1 );
  int month1 = calendar.GetMonth( date1 );
  int year2 = calendar.GetYear( date2 );
  int month2 = calendar.GetMonth( date2 );

  // find the the day to compare
  int compareDay = date2.Day;
  int compareDaysPerMonth = calendar.GetDaysInMonth( year1, month1 );
  if ( compareDay > compareDaysPerMonth )
  {
    compareDay = compareDaysPerMonth;
  }

  // build the compare date
  DateTime compareDate = new DateTime( year1, month2, compareDay,
    date2.Hour, date2.Minute, date2.Second, date2.Millisecond );
  if ( date2 > date1 )
  {
    if ( compareDate < date1 )
    {
      compareDate = compareDate.AddYears( 1 );
    }
  }
  else
  {
    if ( compareDate > date1 )
    {
      compareDate = compareDate.AddYears( -1 );
    }
  }
  return year2 - calendar.GetYear( compareDate );
} // YearDiff

用法:

// ----------------------------------------------------------------------
public void CalculateAgeSamples()
{
  PrintAge( new DateTime( 2000, 02, 29 ), new DateTime( 2009, 02, 28 ) );
  // > Birthdate=29.02.2000, Age at 28.02.2009 is 8 years
  PrintAge( new DateTime( 2000, 02, 29 ), new DateTime( 2012, 02, 28 ) );
  // > Birthdate=29.02.2000, Age at 28.02.2012 is 11 years
} // CalculateAgeSamples

// ----------------------------------------------------------------------
public void PrintAge( DateTime birthDate, DateTime moment )
{
  Console.WriteLine( "Birthdate={0:d}, Age at {1:d} is {2} years", birthDate, moment, YearDiff( birthDate, moment ) );
} // PrintAge

10

这个经典问题值得采用Noda Time解决方案。

static int GetAge(LocalDate dateOfBirth)
{
    Instant now = SystemClock.Instance.Now;

    // The target time zone is important.
    // It should align with the *current physical location* of the person
    // you are talking about.  When the whereabouts of that person are unknown,
    // then you use the time zone of the person who is *asking* for the age.
    // The time zone of birth is irrelevant!

    DateTimeZone zone = DateTimeZoneProviders.Tzdb["America/New_York"];

    LocalDate today = now.InZone(zone).Date;

    Period period = Period.Between(dateOfBirth, today, PeriodUnits.Years);

    return (int) period.Years;
}

用法:

LocalDate dateOfBirth = new LocalDate(1976, 8, 27);
int age = GetAge(dateOfBirth);

您可能还对以下改进感兴趣:

  • 将时钟作为IClock而不是使用SystemClock.Instance可以提高可测试性。

  • 目标时区可能会更改,因此您也需要一个DateTimeZone参数。

另请参阅我关于此主题的博客文章:处理生日和其他纪念日


您是否与Noda Time相关联?
Zimano

我为此做出了贡献,但主要是乔恩·斯基特(Jon Skeet)的。
马特·约翰逊

9

我使用ScArcher2的解决方案来准确地计算人员年龄,但是我需要更进一步,并计算他们的月份和天数以及年份。

    public static Dictionary<string,int> CurrentAgeInYearsMonthsDays(DateTime? ndtBirthDate, DateTime? ndtReferralDate)
    {
        //----------------------------------------------------------------------
        // Can't determine age if we don't have a dates.
        //----------------------------------------------------------------------
        if (ndtBirthDate == null) return null;
        if (ndtReferralDate == null) return null;

        DateTime dtBirthDate = Convert.ToDateTime(ndtBirthDate);
        DateTime dtReferralDate = Convert.ToDateTime(ndtReferralDate);

        //----------------------------------------------------------------------
        // Create our Variables
        //----------------------------------------------------------------------
        Dictionary<string, int> dYMD = new Dictionary<string,int>();
        int iNowDate, iBirthDate, iYears, iMonths, iDays;
        string sDif = "";

        //----------------------------------------------------------------------
        // Store off current date/time and DOB into local variables
        //---------------------------------------------------------------------- 
        iNowDate = int.Parse(dtReferralDate.ToString("yyyyMMdd"));
        iBirthDate = int.Parse(dtBirthDate.ToString("yyyyMMdd"));

        //----------------------------------------------------------------------
        // Calculate Years
        //----------------------------------------------------------------------
        sDif = (iNowDate - iBirthDate).ToString();
        iYears = int.Parse(sDif.Substring(0, sDif.Length - 4));

        //----------------------------------------------------------------------
        // Store Years in Return Value
        //----------------------------------------------------------------------
        dYMD.Add("Years", iYears);

        //----------------------------------------------------------------------
        // Calculate Months
        //----------------------------------------------------------------------
        if (dtBirthDate.Month > dtReferralDate.Month)
            iMonths = 12 - dtBirthDate.Month + dtReferralDate.Month - 1;
        else
            iMonths = dtBirthDate.Month - dtReferralDate.Month;

        //----------------------------------------------------------------------
        // Store Months in Return Value
        //----------------------------------------------------------------------
        dYMD.Add("Months", iMonths);

        //----------------------------------------------------------------------
        // Calculate Remaining Days
        //----------------------------------------------------------------------
        if (dtBirthDate.Day > dtReferralDate.Day)
            //Logic: Figure out the days in month previous to the current month, or the admitted month.
            //       Subtract the birthday from the total days which will give us how many days the person has lived since their birthdate day the previous month.
            //       then take the referral date and simply add the number of days the person has lived this month.

            //If referral date is january, we need to go back to the following year's December to get the days in that month.
            if (dtReferralDate.Month == 1)
                iDays = DateTime.DaysInMonth(dtReferralDate.Year - 1, 12) - dtBirthDate.Day + dtReferralDate.Day;       
            else
                iDays = DateTime.DaysInMonth(dtReferralDate.Year, dtReferralDate.Month - 1) - dtBirthDate.Day + dtReferralDate.Day;       
        else
            iDays = dtReferralDate.Day - dtBirthDate.Day;             

        //----------------------------------------------------------------------
        // Store Days in Return Value
        //----------------------------------------------------------------------
        dYMD.Add("Days", iDays);

        return dYMD;
}

9

SQL版本:

declare @dd smalldatetime = '1980-04-01'
declare @age int = YEAR(GETDATE())-YEAR(@dd)
if (@dd> DATEADD(YYYY, -@age, GETDATE())) set @age = @age -1

print @age  

8

我对马克·索恩(Mark Soen)的答案做了一个小改动:我重写了第三行,以便可以更轻松地解析表达式。

public int AgeInYears(DateTime bday)
{
    DateTime now = DateTime.Today;
    int age = now.Year - bday.Year;            
    if (bday.AddYears(age) > now) 
        age--;
    return age;
}

为了清楚起见,我也将其变成一个函数。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.