我需要检查某个日期距离现在过去了多少年。目前我已经从datetime
模块得到了一个timedelta
,但是我不知道如何将其转换成年份。
你需要不仅仅是一个 timedelta
来计算经过了多少年;你还需要知道开始(或结束)日期。(这与闰年有关。)
你最好使用dateutil.relativedelta
这个第三方模块,如果你想知道某个日期(默认为现在)经过了 n
年后的 datetime
,可以按照以下方式进行操作:
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)
如果您更喜欢使用标准库,答案会稍微复杂一些:
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)
如果今天是2月29日,18年前没有2月29日,这个函数将返回2月28日。如果您想返回3月1日,只需更改最后一个 return
语句为: return from_date.replace(month=3, day=1,
year=from_date.year-years)
你最初的问题是想知道自某个日期以来过了多少年。假设你想得到一个整数年数,你可以基于每年365.2425天进行猜测,然后使用上面定义的yearsago
函数之一进行检查:
def num_years(begin, end=None):
if end is None:
end = datetime.now()
num_years = int((end - begin).days / 365.2425)
if begin > yearsago(num_years, end):
return num_years - 1
else:
return num_years
datetime.now()
)大于平均朱利安(365.25)和格雷戈里(365.2425)年之间的差异。在@Adam Rosenfield的答案中提供了正确的方法。 - jfsdateutil
现在似乎是一个内置的包(至少对于我的来自Miniconda的Python 3.9.6而言)。 - Addison Klinkedate = datetime.strptime("28.02.1981, 23:00:00","%d.%m.%Y, %H:%M:%S") print(date+timedelta(hours=1))
会产生3月1日,而 date = datetime.strptime("28.02.1980, 23:00:00","%d.%m.%Y, %H:%M:%S") print(date+timedelta(hours=1))
会产生2月29日 --> 正确 - EvilSmurf如果您要检查某人是否已满18岁,使用 timedelta
可能在某些边缘情况下不会正确工作,因为闰年的存在。例如,出生于2000年1月1日的人将在6575天后(包括5个闰年)于2018年1月1日刚好年满18岁,但出生于2001年1月1日的人将在6574天后(包括4个闰年)于2019年1月1日刚好年满18岁。因此,如果某人恰好是6574天大,您无法确定他们是否17或18岁,除非您了解有关其出生日期的更多信息。
正确的方法是直接从日期中计算年龄,通过年份相减,然后如果当前日期在出生日期之前,则再减去一岁。
首先,在最详细的层面上,这个问题无法得到精确的解决。年份的长度有所不同,而且没有明确的“正确选择”来确定年份长度。
话虽如此,可以用“自然”的单位(可能是秒)获取差异,然后除以该单位与年份之间的比率。例如:
delta_in_days / (365.25)
delta_in_seconds / (365.25*24*60*60)
...或其他什么。避免使用月份,因为它们比年份的定义还要模糊。
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)))
获取天数,然后除以365.2425(平均公历年)得到年份。除以30.436875(平均公历月)得到月份。
import datetime as dt
from dateutil.relativedelta import relativedelta
dt1 = dt.datetime(1990,2,1)
dt2 = dt.datetime(2021,5,16)
out = relativedelta(dt2, dt1)
print(f'Complete: {out}')
print(f'years:{out.years}, months:{out.months}, days:{out.days}') `
完成:relativedelta(年= +31,月= +3,日= +15)
年份:31,月份:3,天数:15
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
td.days / 365.25
可以得出相当接近的结果。def calculate_age(birthday_date, fmt="%Y-%m-%d"):
birthday = datetime.datetime.strptime(birthday_date, fmt)
age = datetime.datetime.now() - birthday
# first datime valid is (1, 1, 1), I use (1, 12, 31) => (2, 0, 0) to hack the lib
age = (datetime.datetime(1, 12, 31) + age)
return age.year - 2
now : 2019-09-21
print(calculate_age("2019-09-21")) => 2 (Done)
-> age + (1,12,31) = 0004-01-01 23:42:17.767031
print(calculate_age("2020-09-21")) => 0 (Undone)
-> age + (1,12,31) = 0002-12-31 23:46:39.144091
差异是一天。我理解这种差异的原因是由于闰年。
为了纠正这种不期望的行为,您需要使用生日年份来添加结果。
b = birthday
today = datetime.datetime.today()
age = today.year - b.year + (today.month - b.month > 0 or
(today.month == b.month > 0 and
today.day - b.day > 0))