在python中,年龄从出生日期开始

我怎么能从今天的日期和一个人的出生日期找到一个python年龄?出生日期来自Django模型中的DateField。

250873 次浏览

不幸的是,您不能只使用时间数据,因为它使用的最大单位是日,闰年将使您的计算无效。因此,让我们找到年数,然后如果最后一年没有满,就按1调整:

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()称为性能打击是荒谬的,除非在极端特殊的情况下,否则这无关紧要。使用变量的真正原因是数据不一致的风险。

在这种情况下,最经典的问题是如何对待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
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

更新:使用丹尼的解决方案更好

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

    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月29日,你就认为自己在2月28日是“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)

进口日期时间

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

考虑到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))

最简单的方法是使用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

下面是一个用年、月或日来计算一个人年龄的方法。

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

或者如果他出生在2012 - 12 - 17 - t00:00:00, 他在2013 - 01 - 12 t00:00:00上的年龄将是26天

或者如果他出生在2000 - 02年- 29 - t00:00:00, 他在2012 - 02年- 29 - t00:00:00上的年龄将是12年

你需要进口日期时间

代码如下:

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

现在,我们必须给get_date_format ()提供像2000 - 02年- 29 - t00:00:00这样的字符串

它将把它转换为日期类型对象,该对象将被提供给get_person_age (date_birth date_today)

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

如果你想用django模板打印在页面中,那么下面的代码就足够了:

\{\{ birth_date|timesince }}

扩展丹尼的解决方案,但有各种方式来报告年轻人的年龄(注意,今天是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

正如@[Tomasz Zielinski]和@ williams所建议的那样,python-dateutil可以只做5行。

from dateutil.relativedelta import *
from datetime import date
today = date.today()
dob = date(1982, 7, 5)
age = relativedelta(today, dob)


>>relativedelta(years=+33, months=+11, days=+16)`

轻微修改丹尼的解决方案更容易阅读和理解

    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

扩展到丹尼·w·阿代尔回答,也得到month

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
import datetime

今天的日期

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

你的出生年月日

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

你的年龄

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

你可以使用Python 3来完成这一切。只需运行下面的代码就可以了。

# Creating a variables:


greeting = "Hello, "
name = input("what is your name?")
birth_year = input("Which year you were born?")
response = "Your age is "


# Converting string variable to int:


calculation = 2020 - int(birth_year)




# Printing:


print(f'{greeting}{name}. {response}{calculation}')

serializers.py

age = serializers.SerializerMethodField('get_age')


class Meta:
model = YourModel
fields = [..,'','birthdate','age',..]




import datetime


def get_age(self, instance):
return datetime.datetime.now().year - instance.birthdate.year

一个比@DannyWAdairs更优雅的解决方案可能是使用.timetuple() method [Python-doc] .:

from datetime import date


def calculate_age(born):
today = date.today()
return today.year - born.year - (today.timetuple()[1:3] < born.timetuple()[1:3])

你可以很容易地使用它进一步泛化,将它的粒度增加到秒,这样,如果它大于或等于当天的秒数,年龄就会增加,例如,如果born是一个datetime对象:

from datetime import datetime


def calculate_age_with_seconds(born):
today = datetime.now()
return today.year - born.year - (today.timetuple()[1:6] < born.timetuple()[1:6])

这适用于born既是一个date对象,也是一个datetime对象。