Python的timedelta在几年内
我需要检查自某date以来有多less年。 目前我已经从datetime
模块timedelta
,我不知道如何将其转换为年。
你需要超过一个timedelta
来告诉多less年过去了; 你还需要知道开始(或结束)date。 (这是一个闰年的事情。)
你最好的select是使用dateutil.relativedelta
对象 ,但这是第三方模块。 如果您想知道从某个date起的n
年的date时间(默认为现在),您可以执行以下操作:
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)
你的问题最初说你想知道自从某个date以来有多less年了。 假设你想要一个整数年,你可以猜测每年365.25天,然后使用上面定义的任何一个yearsago
函数来检查::
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
如果你想检查是否有18岁以上的人,那么使用timedelta
在某些边缘案例中会因为闰年而无法正常工作。 例如,2000年1月1日出生的人,在2018年1月1日6575天后(即包括5个闰年)将会完全变成1875,而2001年1月1日出生的人, 2019年(包括4个闰年)。 因此,如果某人正好是6574天,那么在不知道有关他们的出生date的更多信息的情况下,无法确定他们是17岁还是18岁。
正确的做法是直接从date计算年龄,减去两年,然后在当前月份/date在出生月份/date之前减去一个年份。
首先,在最详细的层面上,问题不能完全解决。 年份长短不一,对于年份来说,没有明确的“正确select”。
也就是说,无论单位是“自然的”(可能是几秒),除以这个和那个年份之间的比例,就可以得出差异。 例如
delta_in_days / (365.25) delta_in_seconds / (365.25*24*60*60)
…pipe他呢。 远离数月,因为它们比年代更不明确。
这是一个更新的DOBfunction,它可以像人类一样计算生日。
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(平均公历月)几个月。
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
还有另外一个没有提到的第三方lib是mxDateTime(python datetime
和3rd party 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 Copelandbuild议)相比,肯定是一个矫枉过正的问题。
最后,你有什么是math问题。 如果每隔4年我们有一天额外的一天,然后在几天内跳过timedelta,而不是365,但是365 * 4 + 1,这会给你4年的金额。 然后再将其除以4. timedelta /((365 * 4)+1)/ 4 = timedelta * 4 /(365 * 4 +1)
这是我制定的解决scheme,我希望可以帮助;-)
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
你需要的确切程度如何? 如果你担心闰年, td.days / 365.25
会让你相当接近。
即使这个线程已经死了,我可以build议一个工作解决scheme,这个我面临的同样的问题。 这里是(date是格式为dd-mm-yyyy的string):
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
此函数返回两个date之间的差异(以ISO格式作为string,但可以很容易地修改为采取任何格式)
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
我会build议Pyfdate
什么是pyfdate?
鉴于Python的目标是成为一个function强大且易于使用的脚本语言,其处理date和时间的function并不像应该那样用户友好。 pyfdate的目的是通过提供与Python的其他部分一样强大且易于使用的date和时间来处理这种情况。
教程
那么问题似乎相当简单。 你需要检查“全”年的数量,只有等于18,你需要打扰数月和数天。 边缘情况是: endDate.year - startDate.year == 18
,它分为两种情况: startDate.month != endDate.month
和startDate.month == endDate.month
,当你只需要检查天:
def isOfAge(birthDate, age=18): endDate = date.today() years = endDate.year - birthDate.year if years == age: return (birthDate.month < endDate.month or (birthDate.month == endDate.month and birthDate.day < endDate.day)) return years > age
它仍然不止一行lambda,但仍然很短,执行起来似乎很快。