Python timedelta多年

时间:2009-04-19 18:00:40

标签: python datetime timedelta

我需要查看自某个日期以来是否有多少年。目前我从timedelta模块获得datetime,我不知道如何将其转换为年。

21 个答案:

答案 0 :(得分:134)

你需要的不仅仅是timedelta才能知道已经过了多少年;你还需要知道开始(或结束)日期。 (这是闰年的事情。)

您最好的选择是使用dateutil.relativedelta object,但这是第三方模块。如果您想知道某个日期datetime年后的n(默认为现在),您可以执行以下操作::

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语句改为read ::

    return from_date.replace(month=3, day=1,
                             year=from_date.year-years)

你的问题最初说你想知道自某个约会以来已经过了多少年。假设您需要一个整数年,您可以根据每年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

答案 1 :(得分:44)

如果您正在尝试检查某人是否年满18岁,那么因为闰年,使用timedelta无法在某些边缘情况下正常工作。例如,2000年1月1日出生的人,将于2018年1月1日(包括5个闰年)完全在6575天后转为18岁,但2001年1月1日出生的人将在1月1日6574天之后满18岁, 2019年(包括4个闰年)。因此,如果某人正好在6574天之前,你无法确定他们是17岁还是18岁,而不知道他们的出生日期的更多信息。

这样做的正确方法是直接从日期计算年龄,减去两年,然后在出生月/日之前减去当前月/日。

答案 2 :(得分:9)

首先,在最详细的层面上,问题无法准确解决。年份长短不一,并且年份长度没有明确的“正确选择”。

也就是说,无论单位是“自然”(可能是几秒),除以它与年份之间的比例,得到差异。 E.g。

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

......或者其他什么。远离几个月,因为它们的定义甚至不如几年。

答案 3 :(得分:6)

这是一个更新的DOB功能,它以与人类相同的方式计算生日:

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

答案 4 :(得分:3)

获取天数,然后除以365.2425(平均格里高利年)。除以30.436875(平均格里高利月)数月。

答案 5 :(得分:1)

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

答案 6 :(得分:1)

此处未提及的另一个第三方库是mxDateTime(python datetime的前身和第三方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建议),添加相关单个任务的依赖性肯定会有点过分。

答案 7 :(得分:1)

最后你有一个数学问题。如果每4年我们有一个额外的一天让我们在几天内潜水时间,而不是365但是365 * 4 + 1,这将给你4年的金额。然后再将它除以4。 timedelta /((365 * 4)+1)/ 4 = timedelta * 4 /(365 * 4 +1)

答案 8 :(得分: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

答案 9 :(得分:1)

` 简单的解决方案!

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(years=+31,months=+3, days=+15)

年:31,月:3,天:15

答案 10 :(得分:0)

此函数返回两个日期之间的年份差异(以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

答案 11 :(得分:0)

我会建议Pyfdate

  

什么是pyfdate?

     

鉴于Python的目标是成为一个功能强大且易于使用的脚本   语言,它的工作特点   日期和时间不是   他们应该是用户友好的。该   pyfdate的目的是解决这个问题   通过提供功能的情况   处理日期和时间   功能强大且易于使用   其余的Python。

tutorial

答案 12 :(得分:0)

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

答案 13 :(得分:0)

即使这个帖子已经死了,我可能会建议我面对这个同样问题的解决方案。这是(日期是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

答案 14 :(得分:0)

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操作员在洛根的Run电影中运行的代码;)

https://en.wikipedia.org/wiki/Logan%27s_Run_(film)

答案 15 :(得分:0)

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

但是他的方法没有python示例,但这是我最终使用的方法。

输入: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

答案 16 :(得分:0)

我喜欢约翰·米(John Mee)的解决方案,因为它简单易用,而且我不担心在2月28日或3月1日(不是a年)如何确定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

答案 17 :(得分:0)

我会改用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

答案 18 :(得分:0)

迟到聚会,但这将使您准确,轻松地获得年龄(以年为单位):

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

答案 19 :(得分:0)

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

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

答案 20 :(得分:-2)

嗯,问题似乎很容易。 您需要检查“完整”年份的数量,并且只有当它等于18时才需要花费数月和数天。边缘情况为:endDate.year - startDate.year == 18并且它分为两种情况:startDate.month != endDate.monthstartDate.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,但它仍然很短,并且似乎很快执行。