Tôi cần kiểm tra nếu một số năm đã được kể từ một ngày nào đó. Hiện tại tôi đã nhận được timedelta
từ datetime
mô-đun và tôi không biết làm thế nào để chuyển đổi nó thành năm.
Tôi cần kiểm tra nếu một số năm đã được kể từ một ngày nào đó. Hiện tại tôi đã nhận được timedelta
từ datetime
mô-đun và tôi không biết làm thế nào để chuyển đổi nó thành năm.
Câu trả lời:
Bạn cần nhiều hơn một timedelta
để nói bao nhiêu năm đã trôi qua; bạn cũng cần biết ngày bắt đầu (hoặc kết thúc). (Đó là một năm nhuận.)
Đặt cược tốt nhất của bạn là sử dụng dateutil.relativedelta
đối tượng , nhưng đó là mô-đun của bên thứ 3. Nếu bạn muốn biết datetime
đó là n
năm kể từ ngày nào đó (mặc định là ngay bây giờ), bạn có thể làm như sau ::
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)
Nếu bạn muốn gắn bó với thư viện chuẩn, câu trả lời phức tạp hơn một chút ::
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)
Nếu đó là 29/2 và 18 năm trước không có 29/2, chức năng này sẽ trả về 28/11. Nếu bạn muốn trả về 3/1, chỉ cần thay đổi return
câu lệnh cuối cùng để đọc ::
return from_date.replace(month=3, day=1,
year=from_date.year-years)
Câu hỏi của bạn ban đầu cho biết bạn muốn biết đã bao nhiêu năm kể từ ngày nào đó. Giả sử bạn muốn có số nguyên năm, bạn có thể đoán dựa trên 365,25 ngày mỗi năm và sau đó kiểm tra bằng cách sử dụng một trong các yearsago
hàm được xác định ở trên ::
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()
) lớn hơn sự khác biệt giữa năm Julian ( ) và Gregorian ( ) trung bình . 365.25
365.2425
. Cách tiếp cận đúng được đề xuất trong câu trả lời của @Adam Rosenfield
Nếu bạn đang cố kiểm tra xem ai đó đủ 18 tuổi, việc sử dụng timedelta
sẽ không hoạt động chính xác trong một số trường hợp cạnh vì năm nhuận. Ví dụ: một người sinh ngày 1 tháng 1 năm 2000, sẽ tròn 18 chính xác là 6575 ngày sau vào ngày 1 tháng 1 năm 2018 (bao gồm 5 năm nhuận), nhưng một người sinh vào ngày 1 tháng 1 năm 2001 sẽ quay lại 18 chính xác sau 6574 ngày vào ngày 1 tháng 1 năm 2019 (bao gồm 4 năm nhuận). Do đó, nếu bạn có ai đó chính xác là 6574 ngày, bạn không thể xác định họ 17 hay 18 tuổi mà không biết thêm một chút thông tin về ngày sinh của họ.
Cách chính xác để làm điều này là tính tuổi trực tiếp từ các ngày, bằng cách trừ hai năm, sau đó trừ đi một nếu tháng / ngày hiện tại trước tháng sinh / ngày.
Trước hết, ở cấp độ chi tiết nhất, vấn đề không thể được giải quyết chính xác. Năm có độ dài khác nhau và không có "lựa chọn đúng" rõ ràng cho độ dài năm.
Điều đó nói rằng, có được sự khác biệt trong bất kỳ đơn vị nào là "tự nhiên" (có thể là giây) và chia cho tỷ lệ giữa đó và năm. Ví dụ
delta_in_days / (365.25)
delta_in_seconds / (365.25*24*60*60)
...hay bất cứ cái gì. Tránh xa các tháng, vì chúng thậm chí còn ít được xác định rõ hơn so với năm.
Đây là một chức năng DOB được cập nhật, tính toán ngày sinh nhật giống như cách con người làm:
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)))
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
Làm thế nào chính xác để bạn cần nó được? td.days / 365.25
sẽ giúp bạn khá gần, nếu bạn lo lắng về những năm nhuận.
Tuy nhiên, một lib bên thứ 3 khác không được đề cập ở đây là mxDateTime (tiền thân của cả python datetime
và bên thứ 3 timeutil
) có thể được sử dụng cho nhiệm vụ này.
Những điều đã nói ở trên yearsago
sẽ là:
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)
Tham số đầu tiên dự kiến là một DateTime
ví dụ.
Để chuyển đổi thông thường datetime
sang DateTime
bạn có thể sử dụng điều này trong độ chính xác 1 giây):
def DT_from_dt_s(t):
return DT.DateTimeFromTicks(time.mktime(t.timetuple()))
hoặc điều này cho độ chính xác 1 micro giây:
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)
Và vâng, việc thêm sự phụ thuộc cho nhiệm vụ duy nhất này trong câu hỏi chắc chắn sẽ là một sự quá mức so với việc sử dụng timeutil (được đề xuất bởi Rick Copeland).
Cuối cùng, những gì bạn có là một vấn đề toán học. Nếu cứ sau 4 năm chúng ta lại có thêm một ngày thì hãy lặn theo thời gian theo ngày, không phải bằng 365 mà là 365 * 4 + 1, điều đó sẽ cung cấp cho bạn số tiền là 4 năm. Sau đó chia lại cho 4. timedelta / ((365 * 4) +1) / 4 = timedelta * 4 / (365 * 4 +1)
Đây là giải pháp tôi đã thực hiện, tôi hy vọng có thể giúp đỡ ;-)
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
Mặc dù chủ đề này đã chết, tôi có thể đề xuất một giải pháp hiệu quả cho vấn đề tương tự mà tôi đang gặp phải. Đây là (ngày là một chuỗi ở định dạng 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
hàm này trả về chênh lệch theo năm giữa hai ngày (được lấy dưới dạng chuỗi ở định dạng ISO, nhưng nó có thể dễ dàng sửa đổi để lấy ở bất kỳ định dạng nào)
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
Tôi sẽ đề nghị Pyfdate
Pyfdate là gì?
Do mục tiêu của Python là ngôn ngữ kịch bản mạnh mẽ và dễ sử dụng, các tính năng của nó để làm việc với ngày và giờ không thân thiện với người dùng như bình thường. Mục đích của pyfdate là khắc phục tình trạng đó bằng cách cung cấp các tính năng để làm việc với ngày và giờ mạnh mẽ và dễ sử dụng như phần còn lại của Python.
các hướng dẫn
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()
Đây là mã mà nhà điều hành Carrousel đang chạy trong bộ phim Run của Logan;)
Tôi đã xem qua câu hỏi này và thấy Adams trả lời https://stackoverflow.com/a/765862/2964689 hữu ích nhất
Nhưng không có ví dụ nào về phương pháp của anh ta, nhưng đây là những gì tôi đã sử dụng.
đầu vào: đối tượng datetime
đầu ra: tuổi nguyên trong cả năm
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
Tôi thích giải pháp của John Mee vì sự đơn giản của nó và tôi không quan tâm đến việc làm thế nào, vào ngày 28 tháng 2 hoặc ngày 1 tháng 3 khi không phải là năm nhuận, để xác định tuổi của những người sinh vào ngày 29 tháng 2. Nhưng đây là một chỉnh sửa mã của anh ấy mà tôi nghĩ rằng giải quyết các khiếu nại:
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