Tuổi từ ngày sinh ở trăn


159

Làm thế nào tôi có thể tìm thấy một tuổi trong trăn từ ngày hôm nay và ngày sinh của một người? Ngày sinh là từ DateField trong mô hình Django.


4
Khi datetimemô-đun tiêu chuẩn là không đủ, bạn có thể thử: labix.org/python-dateutil
Tomasz Zieliński

1
Điều này gần như chắc chắn đã được giải quyết bằng cách:dateutil.relativedelta.relativedelta
Williams

Câu trả lời:


288

Điều đó có thể được thực hiện đơn giản hơn nhiều khi xem int (True) là 1 và int (Sai) là 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
một nitpick: date.today()trả về ngày trong múi giờ địa phương có thể khác với nơi sinh. Bạn có thể cần phải sử dụng các múi giờ một cách rõ ràng
jfs

10
Điều đó có thể phụ thuộc vào định nghĩa của bạn về "tuổi". Đối với tất cả các mục đích thực tế, sinh nhật thường được đưa ra dưới dạng ngày, không phải là mốc thời gian nhận biết múi giờ (nghĩa là "sinh ra" bị thiếu các chi tiết). Hầu hết mọi người không được sinh ra vào lúc nửa đêm của thời gian nơi sinh của tôi). Nếu "sinh ra" là một mốc thời gian nhận biết múi giờ, bạn có thể sử dụng số học và chuẩn hóa () - có thể quan tâm cho một phần mềm chiêm tinh?
Daniel W. Adair

2
Tôi hoàn toàn đồng ý trong bối cảnh của thời đại con người nhưng công thức của bạn có thể được sử dụng trong bối cảnh rộng hơn. Mặc dù cá nhân tôi không bao giờ tổ chức sinh nhật của tôi thậm chí sớm hơn một giờ do truyền thống gia đình và là một lập trình viên, việc tính toán thời gian mọi lúc mọi nơi là chuyện nhỏ.
jfs

@pyd: sinh ra là một ngày / 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

Cập nhật: Sử dụng giải pháp của Daniel , tốt hơn


2
Theo nguyên tắc, exceptkhối của bạn chỉ nên bắt một ngoại lệ cụ thể có thể được nêu ra.
Daenyth

1
@Daenyth: Cuộc gọi tốt ... Tôi nghĩ đó là một ValueError. Cập nhật.
mở

Tôi thậm chí còn đi xa hơn để kiểm tra thông điệp của ngoại lệ để đảm bảo đó là những gì tôi đang mong đợi. Ngay cả với mã ở trên, có khả năng ném ValueError, nhưng đó không phải là ValueError mà bạn đang mong đợi.
Randy Syring

+ ngoại lệ nhưng, có vấn đề gì trong tôi không? Tôi nghĩ nó khá đơn giản. def calculate_age(dob)
Grijesh Chauhan

1
@GrijeshChauhan: Vâng, của bạn không hoạt động. datetime.date(2014, 1, 1)cho -1, nó sẽ cho 0. Bạn today > dobđang kiểm tra xem DOB có trong quá khứ không, không sớm hơn cùng năm. datetime.date.today()bao gồm thông tin năm, đó là lý do tại sao tôi thay thế nó bằng năm hiện tại trong giải pháp của mình.
mở

18
from datetime import date

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

Trong Python 3, bạn có thể thực hiện phép chia trên datetime.timedelta:

from datetime import date, timedelta

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

2
mỗi năm thứ tư là một năm nhuận trừ năm trăm năm không phải là năm nhuận trừ bốn năm một trăm là một năm nhuận. thử ngày_in_year = 365.2425
Dan

3
@Dan: sự khác biệt giữa Julian ( 365.25) và Gregorian năm dương lịch ( 365.2425) là ít hơn một ngày nếu bạn sống dưới 130 năm.
JFS

4
Điều này không hoạt động trong một số ngày: (date(2017, 3, 1) - date(2004, 3, 1)) / timedelta(days=365.2425)nên trả lại 13, nhưng nó sẽ trả về 12. Không có người yêu, kết quả là 12.999582469181433.
href_

13

Theo đề xuất của @ [Tomasz Zielinski] và @Williams python-dateutil có thể làm điều đó chỉ 5 dòng.

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

Cách đơn giản nhất là sử dụng 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
Điều này không hoạt động chính xác khi sinh nhật vào ngày 29 tháng 2 và ngày hôm nay là 28 tháng 2 (nó sẽ hoạt động như thể hôm nay là ngày 29 tháng 2).
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

ví dụ ngày hoặc một số obj như thế, docs.python.org/3/l Library / datetime.html # datetime.date, đã sửa lỗi chính tả.
gzerone

5

Thật không may, bạn không thể chỉ sử dụng timedelata vì đơn vị lớn nhất mà nó sử dụng là ngày và năm nhuận sẽ khiến bạn tính toán không hợp lệ. Do đó, hãy tìm số năm sau đó điều chỉnh theo một năm nếu năm ngoái không đầy đủ:

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

Cập nhật:

Giải pháp này thực sự gây ra một ngoại lệ khi ngày 29 tháng 2 đi vào hoạt động. Đây là kiểm tra chính xác:

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

Cập nhật2:

Gọi nhiều cuộc gọi đến now()một hit hiệu suất là vô lý, nó không quan trọng trong tất cả nhưng trường hợp cực kỳ đặc biệt. Lý do thực sự để sử dụng một biến là nguy cơ không thống nhất dữ liệu.


Cảm ơn bạn, tôi đã phát hiện ra điều này bằng cách thực hiện một số thử nghiệm - và kết thúc một mã tương tự được tìm thấy từ liên kết của AndiDog.
tkalve

3
Strike 1: Bạn đang sử dụng datetime.datetime thay vì datetime.date. Strike 2: Mã của bạn xấu và không hiệu quả. Gọi datetime.now () BA lần ?? Đột kích 3: Ngày sinh 29 tháng 2 năm 2004 và ngày hôm nay 28 tháng 2 năm 2010 sẽ trở lại 6 tuổi, không phải thét chói tai "ValueError: ngày nằm ngoài phạm vi của tháng". Bạn bị loại!
John Machin

Xin lỗi, mã "Cập nhật" của bạn thậm chí còn nhiều baroque và bị hỏng hơn lần thử đầu tiên - không có gì để làm với ngày 29 tháng 2; nó thất bại trong NHIỀU trường hợp đơn giản như 2009-06-15 đến 2010/07/02 ... người đó rõ ràng là hơn 1 tuổi một chút nhưng bạn đã trừ một năm vì thử nghiệm vào những ngày (2> = 15) không thành công. Và rõ ràng là bạn chưa kiểm tra nó - nó có lỗi cú pháp.
John Machin

4

Gotcha cổ điển trong kịch bản này là những gì cần làm với những người sinh vào ngày 29 tháng 2. Ví dụ: bạn cần đủ 18 tuổi để bỏ phiếu, lái xe, mua rượu, v.v ... nếu bạn sinh vào ngày 2004-2-29, ngày đầu tiên bạn được phép làm những việc đó là gì: 2022-02 -28, hoặc 2022-03-01? AFAICT, chủ yếu là người đầu tiên, nhưng một vài killjoy có thể nói điều sau.

Đây là mã phục vụ cho 0,068% (xấp xỉ) dân số sinh vào ngày đó:

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

Đây là đầu ra:

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

Và gần đây tôi mới biết về bước nhảy vọt thứ hai .
Bobort

3

Nếu bạn đang tìm cách in cái này trong một trang bằng các mẫu django, thì những điều sau đây có thể là đủ:

{{ birth_date|timesince }}

4
Đừng sử dụng Django |timesinceđể tính toán thời gian trong nhiều năm vì nó không tính đến năm nhuận và do đó mang lại kết quả không chính xác. Xem vé Django # 19210 để biết thêm thông tin về điều này.
jnns

Không biết điều đó. Cảm ơn.
Anoyz

2

Đây là một giải pháp để tìm tuổi của một người là năm hoặc tháng hoặc ngày.

Giả sử ngày sinh của một người là 2012-01-17T00: 00: 00 Do đó, tuổi của anh ấy vào 2013-01-16T00: 00: 00 sẽ là 11 tháng

hoặc nếu anh ấy sinh vào ngày 2012-12-17T00: 00: 00 , tuổi của anh ấy vào 2013-01-12T00: 00: 00 sẽ là 26 ngày

hoặc nếu anh ấy sinh vào 2000-02-29T00: 00: 00 , tuổi của anh ấy vào 2012 / 02-29T00 : 00: 00 sẽ là 12 năm

Bạn sẽ cần nhập datetime .

Đây là mã:

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

Một số chức năng bổ sung được sử dụng trong các mã trên là:

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

Bây giờ, chúng ta phải cung cấp get_date_format () với các chuỗi như 2000-02-29T00: 00: 00

Nó sẽ chuyển đổi nó thành đối tượng loại ngày sẽ được cung cấp cho get_person_age (date_birth, date_today) .

Hàm get_person_age (date_birth, date_today) sẽ trả về tuổi ở định dạng chuỗi.


2

Mở rộng về Giải pháp của Daniel , nhưng với đủ mọi cách để báo cáo độ tuổi cho dân gian trẻ hơn (lưu ý, ngày nay là 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'

Mã mẫu:

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

Vì tôi không thấy cách thực hiện chính xác, tôi đã mã hóa lại theo cách này ...

    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)

Giả định là "18" vào ngày 28 tháng 2 khi sinh vào ngày 29 là sai. Hoán đổi giới hạn có thể bị bỏ qua ... đó chỉ là sự thuận tiện cá nhân cho mã của tôi :)


1

Mở rộng cho Daniel W. Adair Trả lời , để có được tháng

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

Ngày mai

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

Ngày sinh của bạn

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

Tuổi của bạn

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

0

nhập thời gian

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

Trong trường hợp của bạn:

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

Giải pháp thay đổi một chút của Daniel để dễ đọc và dễ hiểu hơn

    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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.