把时间差转换成年?

我需要检查一下是否有几年没有约会了。目前,我已经从 datetime模块 timedelta,我不知道如何转换为年。

215053 次浏览

你需要多精确?如果你担心闰年,td.days / 365.25会让你非常接近。

首先,在最详细的层面上,这个问题不能被精确地解决。年的长度各不相同,对于年的长度没有一个明确的“正确选择”。

也就是说,得到任何单位的差异是“自然”(可能是秒) ,除以之间的比例和年。例如。

delta_in_days / (365.25)
delta_in_seconds / (365.25*24*60*60)

... 或者别的什么,远离月份,因为它们比年份更不明确。

如果您试图检查某人是否18岁,使用 timedelta将不能正确地工作在某些边缘情况下,因为闰年。例如,2000年1月1日出生的人,将在2018年1月1日(包括5个闰年)之后正好18岁,而2001年1月1日出生的人,将在2019年1月1日(包括4个闰年)正好6574天之后18岁。因此,如果一个人正好是6574天大,你不能确定他是17岁还是18岁,除非你知道更多关于他生日的信息。

正确的做法是直接从日期中计算出年龄,减去两年,然后如果当前的月/日在出生月/日之前,再减去一年。

你需要不止一个 timedelta来告诉多少年已经过去; 你还需要知道开始(或结束)的日期。(这是闰年的事情。)

您最好的选择是使用 dateutil.relativedelta 对象,但那是第三方模块。如果你想知道从某个日期(默认到现在)开始的 datetimen年,你可以这样做:

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

即使这个线程已经死了,我可以建议一个工作的解决方案,为这个非常相同的问题,我正面临着。在这里(date 是一个格式为 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

这个函数返回两个日期之间年份的差异(采用 ISO 格式的字符串,但是可以很容易地修改为采用任何格式)

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

我建议 同性恋

什么是 pyfdate?

考虑到 Python 的目标是成为一个强大且易于使用的脚本 语言,它的工作特点 日期和时间不像 用户友好,因为他们应该是 Pyfdate 的目的是补救 通过提供功能, 处理日期和时间 功能强大,易于使用 巨蟒剩下的部分。

教程

这里没有提到的另一个第三方库是 mxDateTime (pythondatetime和第三方 timeutil的前身)可以用于此任务。

上述 yearsago将是:

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)

第一个参数应该是 DateTime实例。

要将普通的 datetime转换为 DateTime,你可以使用1秒的精度) :

def DT_from_dt_s(t):
return DT.DateTimeFromTicks(time.mktime(t.timetuple()))

或者这个1微秒的精度:

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)

是的,与使用 timeutil (由 Rick Copeland 建议)相比,为这个任务添加依赖关系肯定是过分的。

得到天数,然后除以365.2425(平均公历年)。除以30.436875(公历月的平均值)表示月份。

最后你得到的是一个数学问题。如果每4年我们有一个额外的一天,那么让时间三角洲以天为单位下降,不是365而是365 * 4 + 1,那就是4年。然后再除以4。 Timedelta/(365 * 4) + 1)/4 = timedelta * 4/(365 * 4 + 1)

这是我想出来的解决办法,希望能有所帮助; -)

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

下面是一个更新的出生日期函数,它和人类一样计算生日:

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

这是洛根的电影《逃跑》中 Carrousel 操作员运行的代码;)

Https://en.wikipedia.org/wiki/logan%27s_run_(film)

我偶然发现这个问题,并发现亚当斯回答最有帮助的 https://stackoverflow.com/a/765862/2964689

但是他的方法中没有 Python 的例子,但是这里是我最后使用的。

Input: datetime 对象

产量: 全年整数年龄

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

我喜欢 John Mee 的解决方案,因为它很简单,而且我并不关心如何在2月28日或3月1日这个不是闰年的日子来确定2月29日出生的人的年龄。不过,我认为这里有一个他的代码的调整,可以解决这些抱怨:

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

相反,我会使用 datetime.date数据类型,因为在检查已经过去了多少年、多少月和多少天时,它更简单:

now = date.today()
birthday = date(1993, 4, 4)
print("you are", now.year - birthday.year, "years,", now.month - birthday.month, "months and",
now.day - birthday.day, "days old")

产出:

you are 27 years, 7 months and 11 days old

当我需要在特定日期执行算术时,我使用 timedelta:

age = now - birthday
print("addition of days to a date: ", birthday + timedelta(days=age.days))

产出:

addition of days to a date:  2020-11-15

参加聚会迟到了,但这个可以准确而容易地给出你的年龄(以年为单位) :

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

` 简单的解决办法!

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

出于我的目的,因为减去两个 datetime对象(至少在 Python 3.8中是这样)会转换为只有一个 days属性的 timedelta:

>>> admit = datetime.strptime('20130530', '%Y%m%d')
>>> birth = datetime.strptime('20010621', '%Y%m%d')
>>> age = (admit - birth).days/365.2425
>>> age
11.940012457476882

这种方法是对 datetime 库的一种破解:

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

差别是一天。我知道差别的原因是由于双性恋(闰年)。

为了纠正这种不希望出现的行为,您需要使用生日年份来添加结果。