【问题标题】:Age from birthdate in pythonpython中从生日算起的年龄
【发布时间】:2010-02-07 17:10:02
【问题描述】:

如何从今天的日期和一个人的生日在 python 中找到年龄?生日来自 Django 模型中的 DateField。

【问题讨论】:

  • 当标准datetime模块不够用时,可以试试:labix.org/python-dateutil
  • 这几乎肯定已通过以下方式解决:dateutil.relativedelta.relativedelta

标签: python


【解决方案1】:

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

【讨论】:

  • a nitpick: date.today() 返回可能与出生地不同的本地时区日期。您可能需要use timezones explicitly
  • 这可能取决于您对“年龄”的定义。出于所有实际目的,生日通常作为日期给出,而不是时区感知的日期时间(即,“出生”缺少详细信息)。大多数人不是在午夜出生(所以通常过早观察:-)),当在不同的时区时,我会假设大多数人在当地时间观察他们的生日(这就是我所做的,我提前 10-12 小时生活我出生地的时间)。如果“出生”是一个时区感知的日期时间,您可以使用 pytz 的算术和 normalize() - 也许对占星术软件感兴趣?
  • 我完全同意在人类年龄的背景下,但你的公式可以在更广泛的背景下使用。尽管由于家庭传统和作为一名程序员,我个人从来没有提前一个小时庆祝我的生日,但无论我身在何处,计算时间都是微不足道的。
  • @pyd: 出生是一个日期/日期时间
  • 不只是int(True) == 1int(False) == 0,事实证明Python允许你对整数进行加减布尔运算,所以你甚至不需要用@987654326包装布尔值@!直到。 1 - True == 0 在 Python 2 和 3 中。
【解决方案2】:
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's solution,这样更好

【讨论】:

  • 原则上,您的except 块应该只捕获可能引发的一个特定异常。
  • @Daenyth:打得好……我想是ValueError。已更新。
  • 我什至甚至去测试异常的消息以确保它是我所期望的。即使使用上面的代码,也有可能抛出 ValueError,但它不是您期望的 ValueError。
  • + 表示异常但是,我的def calculate_age(dob) 有什么问题 我认为这很简单。
  • @GrijeshChauhan:是的,你的行不通。 datetime.date(2014, 1, 1) 给出 -1,它应该给出 0。您的 today &gt; dob 正在检查 DOB 是否在过去,而不是同年早些时候。 datetime.date.today() 包含年份信息,这就是我在解决方案中将其替换为当前年份的原因。
【解决方案3】:
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)

【讨论】:

  • 每第四年是闰年,除了每一百年不是闰年,除非每四百年是闰年。试试 days_in_year=365.2425
  • @Dan:如果你活不到 130 岁,儒略历 (365.25) 和公历年 (365.2425) 之间的差异不到一天。
  • 这不适用于 一些 日期:(date(2017, 3, 1) - date(2004, 3, 1)) / timedelta(days=365.2425) 应该返回 13,但它返回 12。未下限,结果为12.999582469181433
【解决方案4】:

正如@[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)`

【讨论】:

  • 你如何得到总天数的年龄?
【解决方案5】:

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

【讨论】:

  • 当生日是 2 月 29 日并且今天的日期是 2 月 28 日时,这将无法正常工作(它会像今天是 2 月 29 日一样)。
【解决方案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,错字已修复。
【解决方案7】:

不幸的是,您不能只使用 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 - 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

更新2:

多次调用now() 性能受到影响是荒谬的,除了极端特殊的情况外,这无关紧要。使用变量的真正原因是数据不一致的风险。

【讨论】:

  • 谢谢,我通过一些测试发现了这一点 - 并最终从 AndiDog 的链接中找到了类似的代码。
  • 罢工 1:您使用的是 datetime.datetime 而不是 datetime.date。罢工 2:您的代码丑陋且效率低下。调用 datetime.now() THREE 次??罢工 3:出生日期 2004 年 2 月 29 日和今天的日期 2010 年 2 月 28 日应该返回 6 岁,而不是尖叫“ValueError:day is out of range for month”。你出去了!
  • 抱歉,您的“Upd”代码比第一次尝试更加巴洛克和破烂——与 2 月 29 日无关;它在许多简单的情况下都失败了,比如 2009-06-15 到 2010-07-02 ......这个人显然是 1 岁多一点,但你扣除了一年,因为当天 (2 >= 15) 的测试失败。显然你还没有测试它——它包含一个语法错误。
【解决方案8】:

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

{{ birth_date|timesince }}

【讨论】:

  • 不要使用 Django 的 |timesince 来计算几年的时间增量,因为它没有考虑闰年,因此会产生不准确的结果。有关这方面的更多信息,请参阅 Django 票证 #19210。
  • 不知道。谢谢。
【解决方案9】:

这个场景中的经典问题是如何处理 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

【讨论】:

【解决方案10】:

扩展至Danny's Solution,但有各种方式来报告年轻人的年龄(注意,今天是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

【讨论】:

    【解决方案11】:
    import datetime
    

    今天的日期

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

    你的生日

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

    您的年龄

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

    【讨论】:

      【解决方案12】:

      这是一种以年、月或日为单位查找人年龄的解决方案。

      假设一个人的出生日期是 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 岁

      您需要导入日期时间

      代码如下:

      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

      这样的字符串

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

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

      【讨论】:

        【解决方案13】:

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

            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”是错误的。 可以省略交换边界......这只是我的代码的个人方便:)

        【讨论】:

          【解决方案14】:

          扩展到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
          

          【讨论】:

            【解决方案15】:

            导入日期时间

            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
            

            【讨论】:

              【解决方案16】:

              Danny's solution稍作修改,便于阅读和理解

                  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
              

              【讨论】:

                【解决方案17】:

                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
                

                【讨论】:

                  【解决方案18】:

                  您可以使用 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}')
                  

                  【讨论】:

                  • 伙计,来吧...如果您的生日是在 12 月,而您在一月份进行了计算,那么这不会给您一年中 11 个月的正确答案;)。不是要走的路。
                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2012-02-06
                  • 2023-04-04
                  • 1970-01-01
                  • 1970-01-01
                  • 2010-10-14
                  • 2018-07-23
                  • 1970-01-01
                  相关资源
                  最近更新 更多