Saya perlu memeriksa apakah beberapa tahun telah berlalu sejak suatu tanggal. Saat ini saya mendapatkan timedelta
dari datetime
modul dan saya tidak tahu bagaimana mengubahnya menjadi tahun.
Saya perlu memeriksa apakah beberapa tahun telah berlalu sejak suatu tanggal. Saat ini saya mendapatkan timedelta
dari datetime
modul dan saya tidak tahu bagaimana mengubahnya menjadi tahun.
Jawaban:
Anda membutuhkan lebih dari satu timedelta
untuk mengetahui berapa tahun telah berlalu; Anda juga perlu mengetahui tanggal awal (atau akhir). (Ini adalah tahun kabisat.)
Taruhan terbaik Anda adalah menggunakan dateutil.relativedelta
objek , tapi itu adalah modul pihak ke-3. Jika Anda ingin mengetahui datetime
bahwa itu adalah n
tahun dari suatu tanggal (default sekarang), Anda dapat melakukan hal berikut:
from dateutil.relativedelta import relativedelta
def yearsago(years, from_date=None):
if from_date is None:
from_date = datetime.now()
return from_date - relativedelta(years=years)
Jika Anda lebih suka menggunakan pustaka standar, jawabannya sedikit lebih rumit ::
from datetime import datetime
def yearsago(years, from_date=None):
if from_date is None:
from_date = datetime.now()
try:
return from_date.replace(year=from_date.year - years)
except ValueError:
# Must be 2/29!
assert from_date.month == 2 and from_date.day == 29 # can be removed
return from_date.replace(month=2, day=28,
year=from_date.year-years)
Jika 2/29, dan 18 tahun yang lalu tidak ada 2/29, fungsi ini akan mengembalikan 2/28. Jika Anda lebih suka mengembalikan 3/1, ubah saja return
pernyataan terakhir menjadi:
return from_date.replace(month=3, day=1,
year=from_date.year-years)
Pertanyaan Anda awalnya mengatakan Anda ingin tahu sudah berapa tahun sejak suatu tanggal. Dengan asumsi Anda menginginkan bilangan bulat tahun, Anda dapat menebak berdasarkan 365,25 hari per tahun dan kemudian memeriksa menggunakan salah satu yearsago
fungsi yang ditentukan di atas ::
def num_years(begin, end=None):
if end is None:
end = datetime.now()
num_years = int((end - begin).days / 365.25)
if begin > yearsago(num_years, end):
return num_years - 1
else:
return num_years
datetime.now()
) lebih besar daripada perbedaan antara tahun Julian ( ) dan Gregorian ( ) rata - rata . 365.25
365.2425
. Pendekatan yang benar disarankan dalam jawaban @Adam Rosenfield
Jika Anda mencoba memeriksa apakah seseorang berusia 18 tahun, penggunaan timedelta
tidak akan berfungsi dengan benar pada beberapa kasus edge karena tahun kabisat. Misalnya, seseorang yang lahir pada tanggal 1 Januari 2000, akan berusia 18 tahun tepat 6575 hari kemudian pada tanggal 1 Januari 2018 (termasuk 5 tahun kabisat), tetapi seseorang yang lahir pada tanggal 1 Januari 2001, akan berusia 18 tahun tepat 6574 hari kemudian pada tanggal 1 Januari, 2019 (termasuk 4 tahun kabisat). Jadi, jika seseorang berusia tepat 6574 hari, Anda tidak dapat menentukan apakah mereka berusia 17 atau 18 tahun tanpa mengetahui lebih banyak informasi tentang tanggal lahir mereka.
Cara yang benar untuk melakukan ini adalah menghitung usia secara langsung dari tanggal, dengan mengurangi dua tahun, dan kemudian menguranginya jika bulan / hari saat ini mendahului bulan / hari kelahiran.
Pertama, pada tingkat yang paling mendetail, masalah tidak dapat diselesaikan dengan tepat. Panjang tahun bervariasi, dan tidak ada "pilihan tepat" yang jelas untuk lamanya tahun.
Meskipun demikian, dapatkan perbedaan dalam satuan apa pun yang "alami" (mungkin detik) dan bagi dengan rasio antara satuan tersebut dan tahun. Misalnya
delta_in_days / (365.25)
delta_in_seconds / (365.25*24*60*60)
...atau terserah. Hindari berbulan-bulan, karena mereka bahkan kurang didefinisikan dengan baik daripada tahun.
Berikut adalah fungsi DOB yang diperbarui, yang menghitung ulang tahun dengan cara yang sama seperti manusia:
import datetime
import locale
# Source: https://en.wikipedia.org/wiki/February_29
PRE = [
'US',
'TW',
]
POST = [
'GB',
'HK',
]
def get_country():
code, _ = locale.getlocale()
try:
return code.split('_')[1]
except IndexError:
raise Exception('Country cannot be ascertained from locale.')
def get_leap_birthday(year):
country = get_country()
if country in PRE:
return datetime.date(year, 2, 28)
elif country in POST:
return datetime.date(year, 3, 1)
else:
raise Exception('It is unknown whether your country treats leap year '
+ 'birthdays as being on the 28th of February or '
+ 'the 1st of March. Please consult your country\'s '
+ 'legal code for in order to ascertain an answer.')
def age(dob):
today = datetime.date.today()
years = today.year - dob.year
try:
birthday = datetime.date(today.year, dob.month, dob.day)
except ValueError as e:
if dob.month == 2 and dob.day == 29:
birthday = get_leap_birthday(today.year)
else:
raise e
if today < birthday:
years -= 1
return years
print(age(datetime.date(1988, 2, 29)))
Seberapa tepat Anda membutuhkannya? td.days / 365.25
akan membuat Anda cukup dekat, jika Anda khawatir tentang tahun kabisat.
def age(dob):
import datetime
today = datetime.date.today()
if today.month < dob.month or \
(today.month == dob.month and today.day < dob.day):
return today.year - dob.year - 1
else:
return today.year - dob.year
>>> import datetime
>>> datetime.date.today()
datetime.date(2009, 12, 1)
>>> age(datetime.date(2008, 11, 30))
1
>>> age(datetime.date(2008, 12, 1))
1
>>> age(datetime.date(2008, 12, 2))
0
Namun lib pihak ketiga lain yang tidak disebutkan di sini adalah mxDateTime (pendahulu python datetime
dan pihak ketiga timeutil
) dapat digunakan untuk tugas ini.
Yang tersebut di atas yearsago
adalah:
from mx.DateTime import now, RelativeDateTime
def years_ago(years, from_date=None):
if from_date == None:
from_date = now()
return from_date-RelativeDateTime(years=years)
Parameter pertama diharapkan menjadi sebuah DateTime
instance.
Untuk mengonversi biasa datetime
menjadi DateTime
Anda dapat menggunakan ini selama 1 detik presisi):
def DT_from_dt_s(t):
return DT.DateTimeFromTicks(time.mktime(t.timetuple()))
atau ini untuk presisi 1 mikrodetik:
def DT_from_dt_u(t):
return DT.DateTime(t.year, t.month, t.day, t.hour,
t.minute, t.second + t.microsecond * 1e-6)
Dan ya, menambahkan ketergantungan untuk tugas tunggal ini pasti akan menjadi berlebihan dibandingkan dengan menggunakan timeutil (disarankan oleh Rick Copeland).
Pada akhirnya yang Anda miliki adalah masalah matematika. Jika setiap 4 tahun kita memiliki satu hari ekstra, mari kita selami timedelta dalam beberapa hari, bukan 365 tetapi 365 * 4 + 1, itu akan memberi Anda jumlah 4 tahun. Kemudian bagi lagi dengan 4. timedelta / ((365 * 4) +1) / 4 = timedelta * 4 / (365 * 4 +1)
Ini adalah solusi yang saya berhasil, saya harap dapat membantu ;-)
def menor_edad_legal(birthday):
""" returns true if aged<18 in days """
try:
today = time.localtime()
fa_divuit_anys=date(year=today.tm_year-18, month=today.tm_mon, day=today.tm_mday)
if birthday>fa_divuit_anys:
return True
else:
return False
except Exception, ex_edad:
logging.error('Error menor de edad: %s' % ex_edad)
return True
Meskipun utas ini sudah mati, bolehkah saya menyarankan solusi yang berfungsi untuk masalah yang sama yang saya hadapi ini. Ini dia (tanggal adalah string dalam format dd-mm-yyyy):
def validatedate(date):
parts = date.strip().split('-')
if len(parts) == 3 and False not in [x.isdigit() for x in parts]:
birth = datetime.date(int(parts[2]), int(parts[1]), int(parts[0]))
today = datetime.date.today()
b = (birth.year * 10000) + (birth.month * 100) + (birth.day)
t = (today.year * 10000) + (today.month * 100) + (today.day)
if (t - 18 * 10000) >= b:
return True
return False
fungsi ini mengembalikan perbedaan tahun antara dua tanggal (diambil sebagai string dalam format ISO, tetapi dapat dengan mudah dimodifikasi untuk menggunakan format apa pun)
import time
def years(earlydateiso, laterdateiso):
"""difference in years between two dates in ISO format"""
ed = time.strptime(earlydateiso, "%Y-%m-%d")
ld = time.strptime(laterdateiso, "%Y-%m-%d")
#switch dates if needed
if ld < ed:
ld, ed = ed, ld
res = ld[0] - ed [0]
if res > 0:
if ld[1]< ed[1]:
res -= 1
elif ld[1] == ed[1]:
if ld[2]< ed[2]:
res -= 1
return res
Saya akan menyarankan Pyfdate
Apa itu pyfdate?
Mengingat tujuan Python untuk menjadi bahasa skrip yang kuat dan mudah digunakan, fitur-fiturnya untuk bekerja dengan tanggal dan waktu tidak semudah yang seharusnya. Tujuan pyfdate adalah untuk memperbaiki situasi tersebut dengan menyediakan fitur untuk bekerja dengan tanggal dan waktu yang sama kuat dan mudah digunakannya seperti Python lainnya.
yang tutorial
import datetime
def check_if_old_enough(years_needed, old_date):
limit_date = datetime.date(old_date.year + years_needed, old_date.month, old_date.day)
today = datetime.datetime.now().date()
old_enough = False
if limit_date <= today:
old_enough = True
return old_enough
def test_ages():
years_needed = 30
born_date_Logan = datetime.datetime(1988, 3, 5)
if check_if_old_enough(years_needed, born_date_Logan):
print("Logan is old enough")
else:
print("Logan is not old enough")
born_date_Jessica = datetime.datetime(1997, 3, 6)
if check_if_old_enough(years_needed, born_date_Jessica):
print("Jessica is old enough")
else:
print("Jessica is not old enough")
test_ages()
Ini adalah kode yang dijalankan oleh operator Carrousel di film Logan's Run;)
Saya menemukan pertanyaan ini dan menemukan jawaban Adams https://stackoverflow.com/a/765862/2964689 yang paling membantu
Tapi tidak ada contoh python dari metodenya tapi inilah yang akhirnya saya gunakan.
input: objek datetime
keluaran: usia integer dalam satu tahun penuh
def age(birthday):
birthday = birthday.date()
today = date.today()
years = today.year - birthday.year
if (today.month < birthday.month or
(today.month == birthday.month and today.day < birthday.day)):
years = years - 1
return years
Saya menyukai solusi John Mee karena kesederhanaannya, dan saya tidak terlalu peduli tentang bagaimana, pada 28 Februari atau 1 Maret ketika ini bukan tahun kabisat, untuk menentukan usia orang yang lahir pada 29 Februari. Namun berikut ini adalah perubahan kodenya yang menurut saya mengatasi keluhan:
def age(dob):
import datetime
today = datetime.date.today()
age = today.year - dob.year
if ( today.month == dob.month == 2 and
today.day == 28 and dob.day == 29 ):
pass
elif today.month < dob.month or \
(today.month == dob.month and today.day < dob.day):
age -= 1
return age