15 ответов:
Это можно сделать гораздо проще, учитывая, что 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))
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.yearUpdate: Используйте решение Дэнни , оно лучше
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)
Самый простой способ-использовать
python-dateutilimport 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
По предложению @[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 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
К сожалению, вы не можете просто использовать timedelata, так как самая большая единица измерения, которую он использует, - это день, а високосные годы сделают ваши вычисления недействительными. Поэтому давайте найдем число лет, а затем скорректируем на единицу, если последний год не заполнен:
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 - 1Upd:
Это решение действительно вызывает исключение, когда 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 - 1Upd2:
Вызов нескольких вызовов для
now()хита производительности смешон, это не имеет значения в все, кроме исключительно особых случаев. Реальная причина использования переменной-риск несистематичности данных.
Классический пример в этом сценарии - Что делать с людьми, родившимися 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
Вот решение, чтобы найти возраст человека, как годы или месяцы или дни.
Допустим, дата рождения человека - 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")Теперь мы должны кормить get_date_format () строками типа 2000-02-29T00:00:00
Он преобразует его в объект типа date, который должен быть передан вget_person_age(date_birth, date_today) .
Функция get_person_age(date_birth, date_today) вернет возраст в строковом формате.
Если вы хотите напечатать это на странице с использованием шаблонов 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
Поскольку я не видел правильной реализации, я перекодировал свой таким образом...
Предположение о том, что 28 февраля вам будет "18", когда вы родитесь 29-го, просто неверно. Замена границ может быть оставлена без внимания ... это просто личное удобство для моего кода:)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)
Расширить до Danny W. Adair Answer, чтобы получить месяц также
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
Импорт datetime
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 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
Comments