Python timedelta多年

Mig*_*gol 124 python datetime timedelta

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

Ric*_*and 146

你需要的不仅仅是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)
Run Code Online (Sandbox Code Playgroud)

如果您更愿意使用标准库,答案会更复杂一些::

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)
Run Code Online (Sandbox Code Playgroud)

如果它是2/29,而18年前没有2/29,这个功能将返回2/28.如果您宁愿返回3/1,只需将最后一个return语句更改为:

    return from_date.replace(month=3, day=1,
                             year=from_date.year-years)
Run Code Online (Sandbox Code Playgroud)

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

  • 您可以完全准确地使用365.2425(而不是365.25),这会将公历中的400年例外考虑在内. (24认同)
  • 您的功能在英国和香港等国家合法打破,因为它们"蜿蜒"到3月1日的闰年. (3认同)
  • 另见[this](http://infiniteundo.com/post/25326999628/falsehoods-programmers-believe-about-time)和[this](http://infiniteundo.com/post/25509354022/more-falsehoods-programmers - 相信时间)两者都是关于时间不真实的优秀事物清单. (3认同)
  • @brianary:它不会“完全准确”,例如,[本地时区引入的差异(`datetime.now()`)大于*平均*朱利安(`365.25`)和格里高利(` 365.2425`) 年。](http://stackoverflow.com/a/32658742/4279)。[@Adam Rosenfield 的回答](http://stackoverflow.com/a/765862/4279) 中建议了正确的方法 (2认同)

Ada*_*eld 46

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

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

  • 就是这样……除非你从事任何喜欢猜测的部门:健康、地质等。 (3认同)

Mar*_*usQ 9

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

也就是说,获得任何单位"自然"(可能是秒)的差异,并除以它与年份之间的比率.例如

delta_in_days / (365.25)
delta_in_seconds / (365.25*24*60*60)
Run Code Online (Sandbox Code Playgroud)

...管他呢.远离几个月,因为它们的定义甚至不如几年.

  • 您的365.25应为365.2425,以考虑格里高利历的400年例外情况. (3认同)
  • 在服务多少年或某个人达到特定年龄的问题时,这不是任何人的意思或使用的东西。 (2认同)
  • 好吧,问题*可以*正确解决-您可以提前知道哪些年份有闰日和闰秒等等。只是没有非常优雅的方式来做它而不减去年,然后是月,然后是天等等......在两个格式化的日期中 (2认同)

小智 7

` 简单的解决方案!

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}') `
Run Code Online (Sandbox Code Playgroud)

完成:relativedelta(年=+31,月=+3,天=+15)

年:31,月:3,天:15


bri*_*ary 6

获取天数,然后除以 365.2425(平均公历年)数年。除以 30.436875(平均公历月)数月。


ant*_*ero 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)))
Run Code Online (Sandbox Code Playgroud)


edu*_*ffy 5

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


Joh*_*Mee 5

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
Run Code Online (Sandbox Code Playgroud)

  • 叹。(0) 解决 2 月 29 日问题对于任何日期算术都是至关重要的;你只是忽略了它。(1) 你的代码第一次并没有变得更好;您不明白“产生完全相同的输出”是什么?(2)比较today.month和dob.month的三种可能的原子结果(&lt;、==、&gt;);比较 Today.day 和 dob.day 的三种可能的原子结果;3 * 3 == 9 (3) http://stackoverflow.com/questions/2217488/age-from-birthdate-in-python/2218654 (2认同)