Python'da doğum tarihinden yaş


159

Python'da bugünün yaşını ve doğum tarihini nasıl öğrenebilirim? Doğum tarihi, Django modelindeki bir DateField öğesinden bir.


4
Standart datetimemodül yeterli olmadığında deneyebilirsiniz: labix.org/python-dateutil
Tomasz Zieliński

1
Bu neredeyse kesin olarak çözüldü:dateutil.relativedelta.relativedelta
Williams

Yanıtlar:


288

Bu int (True) 'un 1 ve int (False)' in 0 olduğu göz önüne alındığında çok daha basit yapılabilir:

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
bir nitpick: date.today()yerel saat diliminde doğum yerinden farklı olabilecek tarihi döndürür. Zaman dilimlerini açıkça kullanmanız
jfs

10
Bu muhtemelen "yaş" tanımınıza bağlıdır. Tüm pratik amaçlar için, bir doğum günü genellikle tarih olarak verilir, saat dilimine uyan tarih değil (yani "doğmuş" ayrıntılar eksiktir). Çoğu insan gece yarısı keskin doğmaz (bu yüzden genellikle erken gözlemleyin :-)) ve farklı bir saat diliminde, çoğu insanın doğum günlerini yerel saatte gözlemlediğini varsayarım (yaptığım şey, 10-12 saat ileride yaşıyorum doğum yer zamanımın). Eğer "doğmuş" bir saat dilimi farkına sahip bir tarihse, pytz'ın aritmetiğini kullanabilir ve bir astroloji yazılımı için ilginizi çekebilir () - normalize edebilirsiniz ()?
Danny W. Adair

2
İnsanlık bağlamında tamamen katılıyorum, ancak formülünüz daha geniş bir bağlamda kullanılabilir. Bir aile geleneği ve bir programcı olması nedeniyle doğum günümü kişisel olarak asla bir saat önce kutlamasam da, nerede olduğumun zamanını hesaplamak önemsizdir.
jfs

@pyd: born is a date / datetime
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

Güncelleme: Danny'nin çözümünü kullanın , daha iyi


2
Prensip olarak, exceptbloğunuz yalnızca yükseltilebilecek tek bir istisnayı yakalamalıdır.
Daenyth

1
@Daenyth: İyi arama ... Bence bu bir ValueError. Güncellenmiş.
23.Haziran10'da

Hatta beklediğimden emin olmak için istisna mesajını test edecek kadar ileri gidiyorum. Yukarıdaki kodla bile, bir ValueError atılabilir, ancak beklediğiniz ValueError değil.
Randy Syring

+ istisna için, ama benim içinde herhangi bir sorun var mı ? Bence oldukça basit. def calculate_age(dob)
Grijesh Chauhan

1
@GrijeshChauhan: Evet, seninki çalışmıyor. datetime.date(2014, 1, 1)-1 verir, 0 vermelidir today > dob. DOB geçmişte olup olmadığını kontrol ediyor, aynı yılın başlarında değil. datetime.date.today()yıl bilgilerini içerir, bu yüzden çözümümde mevcut yılla değiştiririm.
mpen

18
from datetime import date

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

Python 3'te aşağıdakileri yapabilirsiniz datetime.timedelta:

from datetime import date, timedelta

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

2
her dördüncü yılda bir sıçrama yılı dışında her yüzüncü yıl bir sıçrama yılı değil, her dört yüzüncü yılda bir sıçrama yılı hariç. try days_in_year = 365.2425
Dan

3
@Dan: 130 yıldan daha az yaşıyorsanız Julian ( 365.25) ve Gregoryen takvim yılı ( 365.2425) arasındaki fark bir günden az.
jfs

4
Bu bazı tarihler için işe yaramıyor : (date(2017, 3, 1) - date(2004, 3, 1)) / timedelta(days=365.2425)dönmeli 13, ancak geri dönmeli 12. Döşenmemiş, sonuç 12.999582469181433.
href_

13

@ [Tomasz Zielinski] ve @Williams python-dateutil tarafından önerildiği gibi sadece 5 satır yapabilir.

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

En basit yol 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
Doğum günü 29 Şubat'ta ve bugünün tarihi 28 Şubat olduğunda bu doğru şekilde çalışmaz (bugün 29 Şubat gibi davranacaktır).
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

tarih örneği veya bunun gibi bir nesne, docs.python.org/3/library/datetime.html#datetime.date, yazım hatası düzeltildi.
gzerone

5

Ne yazık ki, zamanın en büyük birimi gün olduğundan ve artık yıllar sizi hesaplamaları geçersiz kılacağı için timedelata'yı kullanamazsınız. Bu nedenle, yıl sayısını bulalım ve son yıl dolu değilse bir ile ayarlayalım:

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

gnc:

29 Şubat devreye girdiğinde bu çözüm gerçekten bir istisnaya neden oluyor. İşte doğru kontrol:

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()Bir performans isabetine birden fazla çağrı yapmak gülünçtür, son derece özel durumlar dışında önemli değildir. Değişken kullanmanın gerçek nedeni veri tutarsızlığı riskidir.


Teşekkür ederim, bunu bazı testler yaparak öğrendim - ve AndiDog'un bağlantısından benzer bir kod buldum.
tkalve

3
İhtar 1: datetime.date yerine datetime.datetime kullanıyorsunuz. İhtar 2: Kodunuz çirkin ve verimsiz. Üç kez datetime.now () çağrılıyor ?? İhtar 3: Doğum tarihi 29 Şubat 2004 ve bugünün tarihi 28 Şubat 2010, "ValueError: gün ayın aralığının dışında" diye çığlık atarak değil, 6 yaşında dönmelidir. Sen yoksun!
John Machin

Üzgünüz, "Upd" kodunuz ilk denemeden daha barok ve kırılmış - 29 Şubat ile ilgisi yok; 2009-06-15 ila 2010-07-02 gibi birçok basit durumda başarısız oluyor ... kişi belli ki 1 yaşın biraz üzerindedir, ancak günlerdeki test (2> = 15) başarısız olduğu için bir yılı düşer. Ve tabii ki test etmediniz - bir sözdizimi hatası içeriyor.
John Machin

4

Bu senaryoda klasik gotcha, 29 Şubat günü doğan insanlarla ne yapılacağıdır. Örnek: Oy vermek, araba kullanmak, alkol almak vb. İçin 18 yaşında olmanız gerekir ... 2004-02-29'da doğuyorsanız, bu tür şeyleri yapmanıza izin verilen ilk gün nedir: 2022-02 -28 veya 2022-03-01? AFAICT, çoğunlukla ilk, ancak birkaç killjoys ikincisini söyleyebilir.

İşte o gün doğan nüfusun% 0,068'ini (yaklaşık) karşılayan kod:

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

İşte çıktı:

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

Ve son zamanlarda artık ikinci bir adım öğrendim .
Bobort

3

Bunu django şablonlarını kullanarak bir sayfada yazdırmak istiyorsanız, aşağıdakiler yeterli olabilir:

{{ birth_date|timesince }}

4
Django en kullanmayın |timesinceo Artık yıllarda dikkate almaz, çünkü birkaç yıl içinde bir timedelta hesaplanması için ve dolayısıyla yanlış sonuçlar verir. Bu konuda daha fazla bilgi için 19210 numaralı Django biletine bakınız.
jnns

Bunu bilmiyordum. Teşekkürler.
Anoyz

2

İşte bir kişinin yaşını yıl, ay veya gün olarak bulmak için bir çözüm.

Diyelim ki bir kişinin doğum tarihi 2012-01-17T00: 00: 00 Bu nedenle, 2013-01-16T00: 00: 00'daki yaşı 11 ay olacak

O doğdu ise veya 00: 2012-12-17T00 00 , onun yaş 2013-01-12T00: 00: 00 olacak 26 gün

veya 2000-02-29T00: 00: 00'da doğmuşsa, 2012-02-29T00: 00: 00'daki yaşı 12 yıl olacaktır.

Tarih saatini içe aktarmanız gerekir .

İşte kod:

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

Yukarıdaki kodlarda kullanılan bazı ekstra işlevler şunlardır:

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

Ve

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

Şimdi get_date_format () yöntemini 2000-02-29T00 : 00: 00 gibi dizelerle beslemeliyiz

Bunu get_person_age (tarih_doğumu, tarih_bugarı) 'na beslenecek tarih türü nesnesine dönüştürür .

Get_person_age (date_birth, date_today) işlevi , çağrıyı dize biçiminde döndürür.


2

Danny'nin Çözümü'nü genişletmek , ancak gençlerin yaşlarını bildirmenin her türlü yolu ile (bugün not alın 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'

Basit kod:

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

Doğru uygulamayı görmediğim için, benimkini bu şekilde kodladım ...

    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)

29 Şubat'ta doğduğu 28 Şubat'ta "18" olduğu varsayımı yanlıştır. Sınırları değiştirmek dışarıda bırakılabilir ... sadece kodum için kişisel bir kolaylık :)


1

Ayı almak için Danny W. Adair Cevap'a uzatın

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

Bugünün tarihi

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

Doğum tarihin

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

Yaşınız

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

0

içe aktarma zamanı

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

Senin durumunda:

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

Daha kolay okuma ve anlama için Danny'nin çözümünü biraz değiştirdi

    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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.