Python timedelta年


Answers:


156

timedelta要说明已经过去了多少年,您需要做更多的工作;您还需要知道开始(或结束)日期。(这是a年。)

最好的选择是使用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语句更改为:

    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

26
您可以使用365.2425(而不是365.25)来完全准确,它考虑到了400年例外(公历)。
brianary

3
对于英国和香港等国家/地区,您的功能在法律上会中断,因为它们会在3月1日“四舍五入”到leap年。
antihero 2013年


3
也看到这个两者都是不看好时间真正的优秀的东西名单。
gvoysey '16

49

如果您要检查某人是否18岁,请使用 timedelta在某些极端情况下将无法正常工作。例如,某人出生于2000年1月1日,将在2018年1月1日(恰好包括5个leap年)之后的16575天整整18岁,但某人在2001年1月1日出生的人,将在1月1日在整整6574天之后整整18岁。 2019(包括4个leap年)。因此,如果某人的年龄恰好是6574天,则在不了解有关其出生日期的更多信息的情况下就无法确定他们是17岁还是18岁。

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


9

首先,在最详细的级别上,无法完全解决问题。年份长短不一,对于年份长短没有明确的“正确选择”。

也就是说,获得“自然”单位(可能是秒)之间的差异,然后除以该单位与年份之间的比率。例如

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

...管他呢。远离月份,因为它们的定义甚至没有几年之久。


2
当服务多少年或一个人达到特定年龄时,这不是任何人的意思或使用的东西。
约翰·马钦

3
您的365.25应该是365.2425,以考虑公历的400年例外。
brianary

1
好吧,这个问题可以正确解决-您可以提前说出哪几年有leap日和leap秒等等。只是,有做的不十分优雅的方式对未减去岁月,那么几个月,那么几天,等...在这两个格式的日期
Litherum

7

这是一个更新的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)))

当dob是2月29日并且当前年不是a年时,这种情况将中断。
Trey Hunner

4

得到天数,然后除以365.2425(平均公历年)为年。除以30.436875(平均公历月)为月。


2
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

2月29日出生的人在接下来的2月28日将被视为达到1岁。
约翰·马钦

好。通过将测试从“今天之后的生日”转换为“今天之前的生日”,校正以适应29日出生的人口的0.08%。这样解决吗?
约翰·米

对于您的示例,它确实可以正常工作!?!如果我将“今天”设置为2009年2月28日,而将出生日期设置为2008年2月29日,则至少对我来说返回零。而不是您建议的1(Python 2.5.2)。不必粗鲁地对待Machin先生。您究竟遇到哪两个约会?
约翰·米

我将再试一次:大多数人出于大多数法律目的将2月29日出生的人视为在接下来的2月28日达到1岁。您的代码在“更正”之前和之后均产生0。实际上,两个版本的代码对于所有9种输入方式(月<==> X天<==>)产生的输出完全相同。BTW 100.0 /(4 * 365 + 1)产生0.068,而不是0.08。
约翰·马钦

2
叹。(0)在任何日期算法中,解决2月29日的问题都是必不可少的;您只是忽略了它。(1)初次使用您的代码效果不佳;您在“产生完全相同的输出”中不了解什么?(2)比较Today.month和dob.month的三个可能的原子结果(<,==,>);比较Today.day和Dob.day的三个可能的原子结果;3 * ==(3)3 9 stackoverflow.com/questions/2217488/...
约翰·马金

1

您需要多精确? td.days / 365.25如果您担心leap年,它将使您更加接近。


我真的很担心leap年。它应该检查人是否超过18岁。
Migol

然后就没有简单的单行代码了,您将不得不解析两个日期并弄清楚该人是否已经过了18岁生日。
eduffy

1

此处未提及的另一个第三方库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实例。

要转换普通datetimeDateTime你可以使用这个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建议)相比,为有问题的单个任务添加依赖绝对是一个过大的杀伤力。


1

最后,您遇到的是数学问题。如果每隔4年我们有额外的一天,那么可以在几天之内(而不是365天,而是365 * 4 +1)潜水timedelta,那么您的时间就是4年。然后再将其除以4。timedelta /((365 * 4)+1)/ 4 = timedelta * 4 /(365 * 4 +1)


如果年份可被100整除,则leap年的内容不适用,除非年份可被400整除。因此,对于2000年:-可被四整除,因此应为leap,但是...-也可被整除一百,所以它不应该是leap年...-它可以被400整除,因此实际上是a年。对于1900:-可被4整除,因此应该是跳跃式的。-它可以被100整除,因此不应跳跃。-它不能被400整除,因此该规则不适用。1900年不是a年。
Jblasco 2013年

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

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

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

0

我建议Pyfdate

什么是pyfdate?

鉴于Python的目标是成为功能强大且易于使用的脚本语言,因此其用于日期和时间的功能并不像应该的那样友好。pyfdate的目的是通过提供与日期和时间一起使用的功能来补救这种情况,这些功能与Python的其余部分一样强大且易于使用。

教程


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

https://zh.wikipedia.org/wiki/Logan%27s_Run_(电影)


0

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

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

输入:日期时间对象

输出:整年的整数年龄

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

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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.