Jawaban:
Itu bisa dilakukan lebih sederhana mengingat bahwa int (Benar) adalah 1 dan int (Salah) adalah 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))
date.today()
mengembalikan tanggal di zona waktu lokal yang mungkin berbeda dari tempat lahir. Anda mungkin perlu menggunakan zona waktu secara eksplisit
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
Pembaruan: Gunakan solusi Danny , lebih baik
except
blok Anda harus menangkap hanya satu pengecualian khusus yang dapat dinaikkan.
ValueError
. Diperbarui.
def calculate_age(dob)
datetime.date(2014, 1, 1)
memberi -1, itu harus memberi 0. Anda today > dob
sedang memeriksa apakah DOB di masa lalu, bukan awal tahun yang sama ini. datetime.date.today()
termasuk informasi tahun, itulah sebabnya saya menggantinya dengan tahun berjalan dalam solusi saya.
from datetime import date
days_in_year = 365.2425
age = int((date.today() - birth_date).days / days_in_year)
Di Python 3, Anda bisa melakukan pembagian pada datetime.timedelta
:
from datetime import date, timedelta
age = (date.today() - birth_date) // timedelta(days=365.2425)
365.25
tahun kalender Julian ( ) dan Gregorian ( 365.2425
) kurang dari sehari jika Anda hidup kurang dari 130 tahun.
(date(2017, 3, 1) - date(2004, 3, 1)) / timedelta(days=365.2425)
harus kembali 13
, tetapi kembali 12
. Unfloored, hasilnya adalah 12.999582469181433
.
Seperti yang disarankan oleh @ [Tomasz Zielinski] dan @Williams python-dateutil dapat melakukannya hanya 5 baris.
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)`
Cara paling sederhana adalah menggunakan 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
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
Sayangnya, Anda tidak bisa hanya menggunakan timedelata karena unit terbesar yang digunakannya adalah hari dan tahun kabisat akan membuat perhitungan Anda tidak valid. Karena itu, mari kita cari jumlah tahun kemudian sesuaikan satu jika tahun lalu tidak penuh:
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
Pembaruan:
Solusi ini benar-benar menyebabkan pengecualian ketika Feb, 29 berperan. Ini cek yang benar:
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:
Memanggil beberapa panggilan ke now()
hit kinerja adalah konyol, itu tidak masalah dalam semua kasus tetapi sangat istimewa. Alasan sebenarnya untuk menggunakan variabel adalah risiko inkosistensi data.
Gotcha klasik dalam skenario ini adalah apa yang harus dilakukan dengan orang yang lahir pada tanggal 29 Februari. Contoh: Anda harus berusia 18 tahun untuk memilih, mengendarai mobil, membeli alkohol, dll ... jika Anda dilahirkan pada 2004-02-29, apa hari pertama Anda diizinkan melakukan hal-hal seperti itu: 2022-02 -28, atau 2022-03-01? AFAICT, kebanyakan yang pertama, tetapi beberapa killjoys mungkin mengatakan yang terakhir.
Berikut kode yang sesuai untuk 0,068% (kurang-lebih) dari populasi yang lahir pada hari itu:
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
Inilah hasilnya:
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
Jika Anda ingin mencetak ini di halaman menggunakan templat Django, maka berikut ini mungkin cukup:
{{ birth_date|timesince }}
|timesince
untuk menghitung timedelta selama beberapa tahun karena itu tidak memperhitungkan tahun kabisat dan karenanya menghasilkan hasil yang tidak akurat. Lihat tiket Django # 19210 untuk info lebih lanjut tentang ini.
Berikut adalah solusi untuk menemukan usia seseorang sebagai tahun atau bulan atau hari.
Katakanlah tanggal lahir seseorang adalah 2012-01-17T00: 00: 00 Karena itu, usianya pada 2013-01-16T00: 00: 00 adalah 11 bulan
atau jika ia dilahirkan pada 2012-12-17T00: 00: 00 , usianya pada 2013-01-12T00: 00: 00 akan menjadi 26 hari
atau jika dia dilahirkan pada 2000-02-29T00: 00: 00 , usianya pada 2012-02-29T00: 00: 00 akan menjadi 12 tahun
Anda perlu mengimpor datetime .
Ini kodenya:
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
Beberapa fungsi tambahan yang digunakan dalam kode di atas adalah:
def get_todays_date():
"""
This function returns todays date in proper date object format
"""
return datetime.now()
Dan
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")
Sekarang, kita harus memberi makan get_date_format () dengan string seperti 2000-02-29T00: 00: 00
Ini akan mengubahnya menjadi objek tipe tanggal yang akan diumpankan ke get_person_age (date_birth, date_today) .
Fungsi get_person_age (date_birth, date_today) akan mengembalikan umur dalam format string.
Memperluas Solusi Danny , tetapi dengan segala macam cara untuk melaporkan usia bagi kaum muda (catatan, hari ini 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'
Kode sampel:
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
Karena saya tidak melihat implementasi yang benar, saya recoded saya dengan cara ini ...
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)
Anggapan sebagai "18" pada tanggal 28 Februari ketika lahir pada tanggal 29 adalah salah. Menukar batas dapat diabaikan ... itu hanya kenyamanan pribadi untuk kode saya :)
Perpanjang ke Danny W. Adair Answer , untuk mendapatkan bulan juga
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
mengimpor datetime
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
Dalam kasus Anda:
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
Sedikit modifikasi solusi Danny untuk memudahkan membaca dan memahami
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
datetime
modul standar tidak cukup, Anda dapat mencoba: labix.org/python-dateutil