Python中生日的年龄


Answers:


288

考虑到int(True)为1且int(False)为0,可以轻松得多:

from datetime import date

def calculate_age(born):
    today = date.today()
    return today.year - born.year - ((today.month, today.day) < (born.month, born.day))

4
nitpick:date.today()返回本地时区中的日期,该日期可能与出生地不同。您可能需要显式使用时区
jfs 2015年

10
那可能取决于您对“年龄”的定义。出于所有实际目的,通常将生日指定为日期,而不是时区感知的日期时间(即“出生”缺少详细信息)。大多数人不是在午夜时分出生(因此通常会过早观察:-)),当我在不同时区时,我认为大多数人会在当地时间观察他们的生日(这是我的工作,我会提前10-12小时生活)我出生地的时间)。如果“出生”是知道时区的日期时间,则可以使用pytz的算术和normalize()-占星术软件可能感兴趣吗?
Danny W. Adair 2015年

2
我完全同意人类时代的观点,但您的公式可能会在更广泛的范围内使用。尽管由于家庭传统和程序员的缘故,我个人甚至从未提前一个小时庆祝生日,但无论我在哪里,计算时间都是微不足道的。
jfs

@pyd:出生是一个日期/日期时间
kjagiello

68
from datetime import date

def calculate_age(born):
    today = date.today()
    try: 
        birthday = born.replace(year=today.year)
    except ValueError: # raised when birth date is February 29 and the current year is not a leap year
        birthday = born.replace(year=today.year, month=born.month+1, day=1)
    if birthday > today:
        return today.year - born.year - 1
    else:
        return today.year - born.year

更新:使用Danny的解决方案更好


2
原则上,您的代码except块应仅捕获可能引发的一个特定异常。
Daenyth 2010年

1
@Daenyth:好电话...我认为是ValueError。更新。
mpen 2010年

我什至可以测试异常消息,以确保其符合我的期望。即使使用上面的代码,也可能会引发ValueError,但不是您期望的ValueError。
兰迪·赛林

+例外,但是,我有什么问题吗?我认为这很简单。def calculate_age(dob)
Grijesh Chauhan 2014年

1
@GrijeshChauhan:是的,你的行不通。datetime.date(2014, 1, 1)给-1,应该给0。您today > dob正在检查DOB是否在过去,而不是在同一年早些时候。datetime.date.today()包括年份信息,这就是为什么我在解决方案中将其替换为当前年份。
mpen 2014年

18
from datetime import date

days_in_year = 365.2425    
age = int((date.today() - birth_date).days / days_in_year)

在Python 3中,您可以对进行除法datetime.timedelta

from datetime import date, timedelta

age = (date.today() - birth_date) // timedelta(days=365.2425)

2
每隔四年是a年,除了Evey百年不是a年,除了每四百年是a年。尝试days_in_year = 365.2425

3
@丹:如果您的生活时间少于130年,则朱利安(365.25)和公历()之间的差365.2425小于一天。
jfs

4
这在某些日期不起作用:(date(2017, 3, 1) - date(2004, 3, 1)) / timedelta(days=365.2425)应该返回13,但是返回12。未铺地板,结果是12.999582469181433
href_


10

最简单的方法是使用 python-dateutil

import datetime

import dateutil

def birthday(date):
    # Get the current date
    now = datetime.datetime.utcnow()
    now = now.date()

    # Get the difference between the current date and the birthday
    age = dateutil.relativedelta.relativedelta(now, date)
    age = age.years

    return age

7
当生日在2月29日,今天的日期是2月28日时,此功能将无法正常工作(就像今天在2月29日一样)。
Trey Hunner

6
from datetime import date

def age(birth_date):
    today = date.today()
    y = today.year - birth_date.year
    if today.month < birth_date.month or today.month == birth_date.month and today.day < birth_date.day:
        y -= 1
    return y

日期实例或类似的obj,docs.python.org / 3 / library / datetime.html#datetime.date,错字已修复。
gzerone

5

不幸的是,您不能仅仅使用timedelata,因为它使用的最大单位是天,leap年将使您的计算无效。因此,让我们找到年数,如果最后一年未满,则将其调整为一:

from datetime import date
birth_date = date(1980, 5, 26)
years = date.today().year - birth_date.year
if (datetime.now() - birth_date.replace(year=datetime.now().year)).days >= 0:
    age = years
else:
    age = years - 1

更新:

当2月29日生效时,此解决方案确实会导致异常。这是正确的检查:

from datetime import date
birth_date = date(1980, 5, 26)
today = date.today()
years = today.year - birth_date.year
if all((x >= y) for x,y in zip(today.timetuple(), birth_date.timetuple()):
   age = years
else:
   age = years - 1

Upd2:

多次致电来now()提高绩效很可笑,这在所有情况下都没有关系,但在非常特殊的情况下。使用变量的真正原因是数据不一致的风险。


谢谢,我通过进行一些测试发现了这一点-最终在AndiDog的链接中找到了类似的代码。
tkalve 2010年

3
警示1:您使用的是datetime.datetime而不是datetime.date。罢工2:您的代码难看且效率低下。调用datetime.now()THREE倍?警示3:生日2004年2月29日和今天的日期2010年2月28日应返回6岁,而不是尖叫“ ValueError:日期超出月份范围”。你出去了!
约翰·马钦

抱歉,您的“已更新”代码比第一次尝试更加巴洛克式和破损-与2月29日无关。它在很多简单的情况下都会失败,例如2009-06-15至2010-07-02 ...这个人显然是1岁多一点,但是您扣除了一年,因为几天(2> = 15)的测试失败了。显然您还没有测试过-它包含语法错误。
约翰·马钦

4

在这种情况下,典型的陷阱是如何处理2月29日出生的人。例如:您必须年满18岁才能投票,开车,买酒等...如果您出生于2004-02-29,那么您被允许做此类事情的第一天是2022-02 -28还是2022-03-01?AFAICT主要是第一个,但有些杀人狂可能会说后者。

以下代码可满足当日出生人口的0.068%(大约)的需求:

def age_in_years(from_date, to_date, leap_day_anniversary_Feb28=True):
    age = to_date.year - from_date.year
    try:
        anniversary = from_date.replace(year=to_date.year)
    except ValueError:
        assert from_date.day == 29 and from_date.month == 2
        if leap_day_anniversary_Feb28:
            anniversary = datetime.date(to_date.year, 2, 28)
        else:
            anniversary = datetime.date(to_date.year, 3, 1)
    if to_date < anniversary:
        age -= 1
    return age

if __name__ == "__main__":
    import datetime

    tests = """

    2004  2 28 2010  2 27  5 1
    2004  2 28 2010  2 28  6 1
    2004  2 28 2010  3  1  6 1

    2004  2 29 2010  2 27  5 1
    2004  2 29 2010  2 28  6 1
    2004  2 29 2010  3  1  6 1

    2004  2 29 2012  2 27  7 1
    2004  2 29 2012  2 28  7 1
    2004  2 29 2012  2 29  8 1
    2004  2 29 2012  3  1  8 1

    2004  2 28 2010  2 27  5 0
    2004  2 28 2010  2 28  6 0
    2004  2 28 2010  3  1  6 0

    2004  2 29 2010  2 27  5 0
    2004  2 29 2010  2 28  5 0
    2004  2 29 2010  3  1  6 0

    2004  2 29 2012  2 27  7 0
    2004  2 29 2012  2 28  7 0
    2004  2 29 2012  2 29  8 0
    2004  2 29 2012  3  1  8 0

    """

    for line in tests.splitlines():
        nums = [int(x) for x in line.split()]
        if not nums:
            print
            continue
        datea = datetime.date(*nums[0:3])
        dateb = datetime.date(*nums[3:6])
        expected, anniv = nums[6:8]
        age = age_in_years(datea, dateb, anniv)
        print datea, dateb, anniv, age, expected, age == expected

这是输出:

2004-02-28 2010-02-27 1 5 5 True
2004-02-28 2010-02-28 1 6 6 True
2004-02-28 2010-03-01 1 6 6 True

2004-02-29 2010-02-27 1 5 5 True
2004-02-29 2010-02-28 1 6 6 True
2004-02-29 2010-03-01 1 6 6 True

2004-02-29 2012-02-27 1 7 7 True
2004-02-29 2012-02-28 1 7 7 True
2004-02-29 2012-02-29 1 8 8 True
2004-02-29 2012-03-01 1 8 8 True

2004-02-28 2010-02-27 0 5 5 True
2004-02-28 2010-02-28 0 6 6 True
2004-02-28 2010-03-01 0 6 6 True

2004-02-29 2010-02-27 0 5 5 True
2004-02-29 2010-02-28 0 5 5 True
2004-02-29 2010-03-01 0 6 6 True

2004-02-29 2012-02-27 0 7 7 True
2004-02-29 2012-02-28 0 7 7 True
2004-02-29 2012-02-29 0 8 8 True
2004-02-29 2012-03-01 0 8 8 True

我最近才了解about
Bobort

3

如果您希望使用django模板在页面中打印此内容,那么以下内容可能就足够了:

{{ birth_date|timesince }}

4
|timesince数年内不要使用Django 来计算时间增量,因为它不考虑leap年,因此产生的结果不准确。有关更多信息,请参见Django票证#19210。
jnns 2013年

不知道 谢谢。
13年

2

这是找到一个人的年龄(数月,数月或数天)的解决方案。

假设某人的出生日期是2012-01-17T00:00:00 因此,他在2013-01-16T00:00:00的年龄将是11个月

或如果他出生于2012-12-17T00:00:00,则他在2013-01-12T00:00:00的年龄为26天

或如果他出生于2000-02-29T00:00:00,则他在2012-02-29T00:00:00的年龄将为12岁

您将需要导入datetime

这是代码:

def get_person_age(date_birth, date_today):

"""
At top level there are three possibilities : Age can be in days or months or years.
For age to be in years there are two cases: Year difference is one or Year difference is more than 1
For age to be in months there are two cases: Year difference is 0 or 1
For age to be in days there are 4 possibilities: Year difference is 1(20-dec-2012 - 2-jan-2013),
                                                 Year difference is 0, Months difference is 0 or 1
"""
years_diff = date_today.year - date_birth.year
months_diff = date_today.month - date_birth.month
days_diff = date_today.day - date_birth.day
age_in_days = (date_today - date_birth).days

age = years_diff
age_string = str(age) + " years"

# age can be in months or days.
if years_diff == 0:
    if months_diff == 0:
        age = age_in_days
        age_string = str(age) + " days"
    elif months_diff == 1:
        if days_diff < 0:
            age = age_in_days
            age_string = str(age) + " days"
        else:
            age = months_diff
            age_string = str(age) + " months"
    else:
        if days_diff < 0:
            age = months_diff - 1
        else:
            age = months_diff
        age_string = str(age) + " months"
# age can be in years, months or days.
elif years_diff == 1:
    if months_diff < 0:
        age = months_diff + 12
        age_string = str(age) + " months" 
        if age == 1:
            if days_diff < 0:
                age = age_in_days
                age_string = str(age) + " days" 
        elif days_diff < 0:
            age = age-1
            age_string = str(age) + " months"
    elif months_diff == 0:
        if days_diff < 0:
            age = 11
            age_string = str(age) + " months"
        else:
            age = 1
            age_string = str(age) + " years"
    else:
        age = 1
        age_string = str(age) + " years"
# The age is guaranteed to be in years.
else:
    if months_diff < 0:
        age = years_diff - 1
    elif months_diff == 0:
        if days_diff < 0:
            age = years_diff - 1
        else:
            age = years_diff
    else:
        age = years_diff
    age_string = str(age) + " years"

if age == 1:
    age_string = age_string.replace("years", "year").replace("months", "month").replace("days", "day")

return age_string

以上代码中使用的一些额外功能是:

def get_todays_date():
    """
    This function returns todays date in proper date object format
    """
    return datetime.now()

def get_date_format(str_date):
"""
This function converts string into date type object
"""
str_date = str_date.split("T")[0]
return datetime.strptime(str_date, "%Y-%m-%d")

现在,我们必须使用类似2000-02-29T00:00:00的字符串来填充get_date_format()

它将转换为日期类型对象,该对象将被馈送到get_person_age(date_birth,date_today)

函数get_person_age(date_birth,date_today)将以字符串格式返回age。


2

扩展了Danny的解决方案,但提供了多种报告年轻人群年龄的方法(请注意,今天是datetime.date(2015,7,17)):

def calculate_age(born):
    '''
        Converts a date of birth (dob) datetime object to years, always rounding down.
        When the age is 80 years or more, just report that the age is 80 years or more.
        When the age is less than 12 years, rounds down to the nearest half year.
        When the age is less than 2 years, reports age in months, rounded down.
        When the age is less than 6 months, reports the age in weeks, rounded down.
        When the age is less than 2 weeks, reports the age in days.
    '''
    today = datetime.date.today()
    age_in_years = today.year - born.year - ((today.month, today.day) < (born.month, born.day))
    months = (today.month - born.month - (today.day < born.day)) %12
    age = today - born
    age_in_days = age.days
    if age_in_years >= 80:
        return 80, 'years or older'
    if age_in_years >= 12:
        return age_in_years, 'years'
    elif age_in_years >= 2:
        half = 'and a half ' if months > 6 else ''
        return age_in_years, '%syears'%half
    elif months >= 6:
        return months, 'months'
    elif age_in_days >= 14:
        return age_in_days/7, 'weeks'
    else:
        return age_in_days, 'days'

样例代码:

print '%d %s' %calculate_age(datetime.date(1933,6,12)) # >=80 years
print '%d %s' %calculate_age(datetime.date(1963,6,12)) # >=12 years
print '%d %s' %calculate_age(datetime.date(2010,6,19)) # >=2 years
print '%d %s' %calculate_age(datetime.date(2010,11,19)) # >=2 years with half
print '%d %s' %calculate_age(datetime.date(2014,11,19)) # >=6 months
print '%d %s' %calculate_age(datetime.date(2015,6,4)) # >=2 weeks
print '%d %s' %calculate_age(datetime.date(2015,7,11)) # days old

80 years or older
52 years
5 years
4 and a half years
7 months
6 weeks
7 days

1

由于我没有看到正确的实现方式,因此以这种方式重新编码了我的代码...

    def age_in_years(from_date, to_date=datetime.date.today()):
  if (DEBUG):
    logger.debug("def age_in_years(from_date='%s', to_date='%s')" % (from_date, to_date))

  if (from_date>to_date): # swap when the lower bound is not the lower bound
    logger.debug('Swapping dates ...')
    tmp = from_date
    from_date = to_date
    to_date = tmp

  age_delta = to_date.year - from_date.year
  month_delta = to_date.month - from_date.month
  day_delta = to_date.day - from_date.day

  if (DEBUG):
    logger.debug("Delta's are : %i  / %i / %i " % (age_delta, month_delta, day_delta))

  if (month_delta>0  or (month_delta==0 and day_delta>=0)): 
    return age_delta 

  return (age_delta-1)

假设在2月28日出生时在29日成为“ 18”是错误的。可以忽略界限...这只是我的代码的个人方便:)


1

扩展到Danny W. Adair答案,还可以获得月份

def calculate_age(b):
    t = date.today()
    c = ((t.month, t.day) < (b.month, b.day))
    c2 = (t.day< b.day)
    return t.year - b.year - c,c*12+t.month-b.month-c2

1
import datetime

今天的日期

td=datetime.datetime.now().date() 

你的生日

bd=datetime.date(1989,3,15)

你的年龄

age_years=int((td-bd).days /365.25)

0

导入日期时间

def age(date_of_birth):
    if date_of_birth > datetime.date.today().replace(year = date_of_birth.year):
        return datetime.date.today().year - date_of_birth.year - 1
    else:
        return datetime.date.today().year - date_of_birth.year

在您的情况下:

import datetime

# your model
def age(self):
    if self.birthdate > datetime.date.today().replace(year = self.birthdate.year):
        return datetime.date.today().year - self.birthdate.year - 1
    else:
        return datetime.date.today().year - self.birthdate.year

0

稍微修改了Danny的解决方案,以便于阅读和理解

    from datetime import date

    def calculate_age(birth_date):
        today = date.today()
        age = today.year - birth_date.year
        full_year_passed = (today.month, today.day) < (birth_date.month, birth_date.day)
        if not full_year_passed:
            age -= 1
        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.