Pythonでの誕生日からの年齢


159

今日の日付と人の誕生日からPythonで年齢を見つけるにはどうすればよいですか?生年月日は、DjangoモデルのDateFieldからのものです。


4
標準の場合はdatetime、モジュールが十分ではありません、あなたが試すことができます:labix.org/python-dateutil
トマスツ・ジーリンスキー

1
このことは、ほぼ間違いによって解決されています:dateutil.relativedelta.relativedelta
ウィリアムズ

回答:


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

10
それはおそらくあなたの「年齢」の定義に依存します。すべての実用的な目的のために、誕生日は通常、タイムゾーン対応の日時ではなく日付として与えられます(つまり、「生まれた」には詳細がありません)。ほとんどの人は深夜に生まれるわけではないので(通常、時期尚早に観察します:-))、別のタイムゾーンにいるとき、ほとんどの人は現地時間で誕生日を観察していると思います(私がそうしているように、私は10〜12時間先に住んでいます)私の出生地時間の)。「生まれた」がタイムゾーンを認識する日時だった場合、pytzの算術演算とnormalize()を使用できます。おそらく占星術ソフトウェアに関心がありますか。
ダニーW.アデア2015

2
私は人間の年齢の文脈で完全に同意しますが、あなたの公式はより広い文脈で使われるかもしれません。個人的には、家族の伝統とプログラマーであるため、1時間早くさえ私の誕生日を祝うことはありませんが、どこにいても時間を計算するのは簡単です。
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

更新:ダニーのソリューションを使用してください、それはより良いです


2
原則として、exceptブロックは発生する可能性のある特定の例外を1つだけキャッチする必要があります。
Daenyth、

1
@Daenyth:いいね...だと思うValueError。更新しました。
mpen

私は、例外のメッセージをテストして、それが私が期待しているものであることを確認することさえします。上記のコードを使用しても、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
4年ごとはうるう年です。ただし、100年目はうるう年ではなく、400年ごとがうるう年です。days_in_year = 365.2425
Dan

3
@ダン:ユリウス暦(365.25)とグレゴリオ暦の年(365.2425)の差は、130歳未満の場合、1日未満です。
jfs 2014年

4
これは一部の日付では機能しません。を返す(date(2017, 3, 1) - date(2004, 3, 1)) / timedelta(days=365.2425)必要13がありますが、を返します12。フローリングされていない場合、結果は12.999582469181433です。
href_ 2017年

13

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

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

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

日付インスタンスまたはそのようないくつかのオブジェクト、docs.python.org / 3 / library / datetime.html#datetime.date、タイプミス修正。
gzerone 2017年

5

残念ながら、timedelataを使用することはできません。最大の単位は日であり、うるう年は計算を無効にするためです。したがって、年数を見つけて、最後の年がいっぱいでない場合は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()パフォーマンスヒットへの複数の呼び出しはばかげています。非常に特殊な場合を除いて、それはすべて問題ではありません。変数を使用する本当の理由は、データの不整合のリスクです。


ありがとう、私はいくつかのテストを行ってこれを見つけました-そしてAndiDogのリンクから見つけられた同様のコードに終わりました。
tkalve

3
ストライク1:datetime.dateではなくdatetime.datetimeを使用しています。ストライク2:コードは醜く、非効率的です。datetime.now()を3回呼び出しますか?ストライク3:生年月日2004年2月29日、今日の日付2010年2月28日は6歳を返すはずです。「ValueError:日が月の範囲外です。あなたは外にいる!
John Machin

申し訳ありませんが、「Upd」コードは最初の試みよりもはるかにバロックで壊れています。2月29日とは関係ありません。2009-06-15から2010-07-02のような多くの単純なケースでは失敗します...その人は明らかに1歳を少し上回っていますが、日(2> = 15)のテストが失敗するため、1年差し引きます。そして、明らかにそれをテストしていません-構文エラーが含まれています。
John Machin、2010

4

このシナリオの古典的な落とし穴は、2月29日に生まれた人々をどうするかです。例:投票、車の運転、アルコールの購入などを行うには、18歳である必要があります... 2004-02-29で生まれた場合、そのようなことを行うことが許可されている最初の日は次のとおりです:2022-02 -28、または2022-03-01?AFAICT、ほとんどが最初ですが、いくつかのkilljoysは後者を言うかもしれません。

その日に生まれた人口の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

そして最近、うるう秒について学びました。
Bobort 2017年

3

これをdjangoテンプレートを使用してページに印刷する場合は、次の方法で十分です。

{{ birth_date|timesince }}

4
|timesinceうるう年は考慮されないため、不正確な結果が生じるため、Djangoを使用して数年にわたるtimedeltaを計算しないでください。詳細については、Djangoチケット#19210を参照してください。
jnns 2013年

それを知りませんでした。ありがとう。
Anoyz 2013年

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

ここで、get_date_format()に2000-02-29T00:00:00のような文字列をフィードする必要があります

それをget_person_age(date_birth、date_today)に供給される日付型オブジェクトに変換します。

関数get_person_age(date_birth、date_today)年齢を文字列形式で返します。


2

ダニーのソリューションを拡張しますが、若い人々の年齢を報告するためのあらゆる種類の方法を使用します(注、今日はです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 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

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

読みやすく、理解しやすいように少し変更したダニーのソリューション

    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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.