อายุตั้งแต่วันเกิดในหลาม


159

ฉันจะหาอายุในไพ ธ อนได้อย่างไรจากวันนี้และวันเกิดของคน ๆ หนึ่ง? วันเกิดมาจาก DateField ในรูปแบบ Django


4
เมื่อdatetimeโมดูลมาตรฐานไม่เพียงพอคุณสามารถลอง: labix.org/python-dateutil
Tomasz Zieliński

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
อาจขึ้นอยู่กับคำจำกัดความของคุณว่า "อายุ" สำหรับวัตถุประสงค์ในทางปฏิบัติทั้งหมดมักจะได้รับวันเกิดเป็นวันที่ซึ่งไม่ใช่ช่วงเวลาที่รับรู้เขตเวลา (เช่น "เกิด" ไม่มีรายละเอียด) คนส่วนใหญ่ไม่ได้เกิดในเวลาเที่ยงคืนที่คมชัด (มักจะสังเกตก่อนเวลา :-)) และเมื่ออยู่ในเขตเวลาที่แตกต่างกันฉันจะสมมติว่าคนส่วนใหญ่สังเกตวันเกิดของพวกเขาในเวลาท้องถิ่น (นั่นคือสิ่งที่ฉันทำ ของเวลาเกิดของฉัน) หาก "เกิด" เป็นช่วงเวลาที่ทราบเวลาของเขตเวลาคุณสามารถใช้เลขคณิตของ pytz และทำให้ปกติ () - อาจเป็นที่สนใจของซอฟต์แวร์โหราศาสตร์หรือไม่?
Danny W. Adair

2
ฉันเห็นด้วยอย่างสมบูรณ์ในบริบทของวัยมนุษย์ แต่อาจใช้สูตรของคุณในบริบทที่กว้างขึ้น แม้ว่าโดยส่วนตัวแล้วฉันไม่เคยฉลองวันเกิดของฉันแม้แต่ชั่วโมงก่อนหน้านี้เนื่องจากประเพณีของครอบครัวและเป็นโปรแกรมเมอร์มันเป็นเรื่องยากที่จะคำนวณเวลาที่ฉันอยู่
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

อัปเดต:ใช้โซลูชันของ Dannyดีกว่า


2
ตามหลักการแล้วexceptบล็อกของคุณควรได้รับการยกเว้นเพียงข้อเดียวเท่านั้นที่สามารถยกขึ้นมาได้
Daenyth

1
@Daenyth: โทรดี ... ValueErrorฉันคิดว่ามันเป็น Updated
mpen

ฉันยังไปถึงเพื่อทดสอบข้อความของข้อยกเว้นเพื่อให้แน่ใจว่าเป็นสิ่งที่ฉันคาดหวัง แม้ว่าจะมีรหัสด้านบนมีความเป็นไปได้ที่ ValueError จะถูกโยน แต่ไม่ใช่ ValueError ที่คุณคาดหวัง
Randy Syring

+ ยกเว้น แต่มีปัญหาในฉันหรือไม่ ฉันคิดว่ามันค่อนข้างง่าย def calculate_age(dob)
Grijesh Chauhan

1
@GrijeshChauhan: ใช่คุณไม่ทำงาน datetime.date(2014, 1, 1)ให้ -1, มันควรให้ 0 คุณtoday > dobกำลังตรวจสอบว่า DOB เคยเป็นมาก่อนหรือไม่ปีก่อนหน้านี้ datetime.date.today()รวมข้อมูลปีซึ่งเป็นสาเหตุที่ฉันแทนที่ด้วยปีปัจจุบันในโซลูชันของฉัน
mpen

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
ทุก ๆ ปีที่สี่เป็นปีอธิกสุรทินยกเว้นปีที่ร้อยไม่ใช่ปีอธิกสุรทินยกเว้นทุกสี่ร้อยปีเป็นปีอธิกสุรทิน ลองใช้ days_in_year = 365.2425
Dan

3
@Dan: ความแตกต่างระหว่าง Julian ( 365.25) และ Gregorian ปีปฏิทิน ( 365.2425) น้อยกว่าหนึ่งวันถ้าคุณอาศัยอยู่น้อยกว่า 130 ปี
jfs

4
วิธีนี้ใช้ไม่ได้กับบางวัน: (date(2017, 3, 1) - date(2004, 3, 1)) / timedelta(days=365.2425)ควรกลับมา13แต่กลับมา12แล้ว Unfloored 12.999582469181433ผลที่ได้คือ
href_

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
สิ่งนี้ไม่ทำงานอย่างถูกต้องเมื่อวันเกิดวันที่ 29 กุมภาพันธ์และวันที่วันนี้คือ 28 กุมภาพันธ์ (มันจะทำหน้าที่เหมือนวันนี้คือ 29 กุมภาพันธ์)
แต้ม 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

อินสแตนซ์วันที่หรือ obj บางอย่างเช่นนั้น docs.python.org/3/library/datetime.html#datetime.date, พิมพ์ผิดได้รับการแก้ไข
gzerone

5

น่าเสียดายที่คุณไม่สามารถใช้ไทม์เดลาเพียงเพราะหน่วยที่ใหญ่ที่สุดที่ใช้คือวันและปีอธิกสุรทินจะทำให้การคำนวณของคุณไม่ถูกต้อง ดังนั้นให้หาจำนวนปีแล้วปรับทีละหนึ่งถ้าปีที่แล้วไม่เต็ม:

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

UPD:

การแก้ปัญหานี้ทำให้เกิดข้อยกเว้นจริง ๆ เมื่อ ก.พ. 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.datetime แทน datetime.date Strike 2: รหัสของคุณน่าเกลียดและไม่มีประสิทธิภาพ โทร datetime.now () สามครั้ง ?? การนัดหยุดงาน 3: วันเกิด 29 กุมภาพันธ์ 2547 และวันนี้วันที่ 28 ก.พ. 2010 ควรกลับอายุ 6 ไม่ตายเสียงกรีดร้อง "ValueError: วันอยู่นอกช่วงของเดือน" คุณออกไป!
John Machin

ขออภัยรหัส "อัปเดต" ของคุณยิ่งกว่าบาร็อคและแตกหักไปกว่าความพยายามครั้งแรก - จะไม่ทำอะไรกับ 29 กุมภาพันธ์ มันล้มเหลวในหลาย ๆ กรณีเช่น 2009-06-15 ถึง 2010-07-02 ... บุคคลนั้นอายุมากกว่า 1 ปีเล็กน้อย แต่คุณหักปีเนื่องจากการทดสอบในวัน (2> = 15) ล้มเหลว และแน่นอนว่าคุณยังไม่ได้ทดสอบ - มันมีข้อผิดพลาดทางไวยากรณ์
John Machin

4

Gotcha แบบคลาสสิกในสถานการณ์นี้เป็นสิ่งที่ต้องทำกับผู้ที่เกิดในวันที่ 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

และเมื่อเร็ว ๆ นี้ผมเพิ่งได้เรียนรู้เกี่ยวกับสองก้าวกระโดด
Bobort

3

หากคุณต้องการพิมพ์สิ่งนี้ในหน้าโดยใช้เทมเพลต django สิ่งต่อไปนี้อาจเพียงพอ:

{{ birth_date|timesince }}

4
อย่าใช้ Django ใน|timesinceการคำนวณ timedelta ในช่วงเวลาหลายปีเพราะมันไม่ได้อธิบายถึงการกระโดดปีและทำให้ผลลัพธ์ที่ไม่ถูกต้อง ดูตั๋ว Django # 19210 สำหรับข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้
jnns

ไม่ทราบว่า ขอบคุณ
Anoyz

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

คุณจะต้องนำเข้าวันที่และเวลา

นี่คือรหัส:

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

ขยายโซลูชันของ Dannyออกไป แต่ด้วยวิธีการที่หลากหลายในการรายงานอายุของชาวบ้านรุ่นน้อง (หมายเหตุวันนี้คือ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)

การสันนิษฐานว่าเป็น "18" ในวันที่ 28 กุมภาพันธ์เมื่อเกิดวันที่ 29 นั้นผิด การแลกเปลี่ยนขอบเขตสามารถปล่อยทิ้งไว้ ... มันเป็นเพียงความสะดวกสบายส่วนตัวสำหรับรหัสของฉัน :)



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

โซลูชันของ Dannyแก้ไขเล็กน้อยเพื่อให้ง่ายต่อการอ่านและทำความเข้าใจ

    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.