题 如何计算C#中某人的年龄?


鉴于一个 DateTime 代表一个人的生日,我如何计算他们的年龄?


1744


起源


迄今为止所有答案都遗漏的是,这取决于人的出生地和现在的位置。 - Yaur
@Yaur:只需将现在+出生的时间转换为GMT / UTC,年龄只是一个相对值,因此时区是无关紧要的。要确定用户的当前时区,您可以使用GeoLocating。 - Stefan Steiger
为什么不考虑[朱利安日期] [1]? [1]: stackoverflow.com/questions/7103064/... - Muhammad Hewedy
如果我们考虑@Yaur关于跨时区计算的建议,那么Day Light Saving Time应该以任何方式影响计算吗? - DDM
没有人考虑过闰年?或检查月份? - Crash Override


答案:


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

// 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 > today.AddYears(-age)) age--;

但是,这假设您正在寻找 西 年龄的想法,而不是使用 东亚计算


1721



只是想对DateTime.Now性能发表评论。如果您不需要准确的时区值,请使用DateTime.UtcNow它更快。 - JAG
鉴于我们正在谈论生日,你可以使用DateTime.Today,因为时间部分没有相关性。 - Tristan Warner-Smith
此答案不适用于所有语言环境和所有年龄段。一些国家在现有生活者出生后跳过了日期,包括俄罗斯(1918年),希腊(1924年)和土耳其(1926年)。 - Lars D
实际上,它仍然不完全正确。此代码假定'bday'是DateTime的日期部分。这是一个边缘情况(我想大多数人只会传递日期而不是日期时间),但是如果你过了一个生日作为时间大于00:00:00的日期和时间那么你'我会遇到Danvil指出的bug。设置bday = bday.Date解决了这个问题。 - Øyvind
最后一行让我想得太多了。相反如何:if(bday.AddYears(age)> now)age--;这似乎是一个更直观的表达。 - cdiggins


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

894



霍瑞为 yyyymmdd。我用过的第一个数据库产品 P叫做Personal Computer(大约1981年)以这种格式存储日期。任何类型的日期操作都非常容易。 - radarbob
实际上这对于使用datetime-fields的MS-SQL非常有用(自01-011900以来的总天数) - Patrik Eckebrecht
@numerek请将您建议的修改发布为自己的答案。对于它的价值而言,当前年份10000的整数溢出远不及两个数量级。 20,150,000 vs 2,147,483,648 - GalacticCowboy
@LongChalk 20180101 - 20171231 = 8870。删除最后4位数,你有(隐含的) 0 为了这个年龄。你怎样得到 1? - Rufus L
@flindeberg是的,这就是我对LongChalk说的话...... - Rufus L


我不知道如何接受错误的解决方案。 正确的C#片段由Michael Stum撰写

这是一个测试片段:

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

在这里你有方法:

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

345



输出为-Test 9 9 8 - MoXplod
虽然这段代码有效,但它断言,闰日出生的人在3月1日非闰年而不是2月28日达到第二年。事实上, 两种选择都可能是正确的。 维基百科有话要说。因此,虽然您的代码并非“错误”,但也不是可接受的解决方案。 - Matt Johnson
@MattJohnson我认为这是正确的。如果我的bday是2月29日,那么2月28日我的bday还没有过去,我应该和2月27日的年龄相同。然而,3月1日,我们已经过了我的bday,我应该是下一个年龄。在美国,销售酒精的企业会有一个标志,上面写着“如果你在YYYY之后出生,那么你就不能购买酒精”(YYYY每年都会改变)。这意味着2月29日出生的人在他们年满21岁(大多数地方)的那一年不能在2月28日购买酒精,并且支持他们在3月1日之前不会大一岁的想法。 - jfren484
@ jfren484 - 阅读维基百科文章。它在各个司法管辖区之间差异很大。 - Matt Johnson
@ jfren484你的主张完全与哲学无关;但一切都与 你个人的感受。当2月29日出生的人“年龄”在很大程度上不重要,除非年龄形成“法定年龄边界”(例如可以购买酒精,投票,领取养老金,加入军队,获得驾驶执照)。考虑美国的饮酒年龄(21岁):对于大多数人来说是7670天。如果在闰年2月29日之前或闰年之前的3月1日出生,则为7671天。如果出生于2月29日:2月28日是7670天,3月1日是7671天。 选择是任意的 它可以去任何一种方式。 - Craig Young


我认为迄今为止的任何答案都没有提供以不同方式计算年龄的文化。例如,参见 东亚时代的清算 与西方相比。

任何 真实 答案必须包括本地化。该 战略模式 在这个例子中可能是有序的。


115



从你提供的维基百科文章中可以看出:“在中国和日本,它被用于传统的算命或宗教信仰,它在城市人们之间的日常生活中消失了。” - some
@some - 韩国人仍然主要使用这个系统。 - Justin L.
实际上这个概念非常重要 - 人们不喜欢被错误地告知他们的个人信息。例如,我的一半家庭住在马来西亚,一半住在英国。现在,当我与家人的一方而不是另一方时,我的年龄被认为高出两年。 - Phil Gan
不仅我们这个系统主要在韩国使用,而且作为一个与当地人讨论年龄的游客,当地人会礼貌地在出生年份之前互相提及自己。我不是25岁,我是87岁。我更喜欢这种方法。更多'国际生日时间格式' - Dean Rather
在越南,即使使用西方系统,在日常生活中,仅通过减去年数来计算年龄。日期被排除在外 - phuclv


对此的简单回答是申请 AddYears 如下所示,因为这是闰年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
}

99



关于2月29日生日3月1日的评论,从技术上讲,在28日举行是太早了(事实上提前1天)。一天是太晚了一天。但是,由于生日介于两者之间,使用第一个来计算非闰年的年龄对我来说更有意义,因为那个人确实在每年的3月1日(以及第2和第3年),但不是2月28日。 - CyberClaw


我的建议

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

这似乎在正确的日期改变了一年。 (我现在测试到107岁)


76



365.255来自哪里?我认为这不会起作用。 - dreeves
一年365天。闰年+0.25。其他更正为+0.005 - James Curran
我不认为Harry Patch会赞赏你的现场测试方法: latimes.com/news/obituaries/... - MusiGenesis
格里高利历中一年的平均长度为365.2425天。 - dan04
^^因为有时它很重要。在我的测试中,这个人在生日那天失败了,它报告说他们比他们年轻。 - ChadT


另一个功能,不是我,而是在网上找到并稍微改进了一下:

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年的中国人:-)


65



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


我迟到了,但这是一个单行:

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

44



这已破了。 make testable:public static int CalculateAge(DateTime dateOfBirth,DateTime dateToCalculateAge){return new DateTime(dateToCalculateAge.Subtract(dateOfBirth).Ticks).Year - 1;当我输入1990-06-01并计算他14岁生日(1990-05-31)之前的那个年龄时给出了14岁。 - Kjensen


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,因为它们会在闰年中改变天数
  • 为了便于阅读,我已经添加了更多的行

再说一遍......我会为它创建2个静态重载方法,一个用于通用,第二个用于友好性:

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

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

44