如何处理时间间隔的总和和乘法?

时间:2019-04-12 13:27:20

标签: python python-dateutil relativedelta

我需要在添加deadline(int)N之后计算interval(日期时间)(用relativedelta表示,因为它可以是几个月或几年,还可以是秒或日期) 。我可以简单地通过将interval乘以N并将其加到start_date(日期时间)来做到这一点。同时,我需要分多个步骤进行操作,例如计算第5个截止日期,第6个...,所以我只需将interval添加到start_dateN次。 在某些情况下,这两种方法会提供不同的结果。

假设start_date = datetime(年= 2019,month = 1,day = 2),interval = relativedelta(months = 1,days = 2),并且N = 16 。 从一种观点来看,两种方法都是正确的,因为interval*16 = relativedelta(年= + 1,月= + 4,天= + 32),start_date+16*interval = 2019-01-01 + 1年+ 4个月+ 32天= 2020/05/1 + 32天= 2020-06-02(因为可能有31天)。 同时,当我们将它们一一添加时,结果为2020/05/1 + 1个月+ 2天= 2020/06/02

问题与“月-日溢出”有关,但我不知道如何处理。始终使用总和而不是乘法?但这并不安全(想象第9999999个截止日期,间隔为1天1秒)

复制步骤:

def test_relative_sum_mult_with_date():
    start = datetime(year=2019, month=1, day=1)
    interval = relativedelta(months=1, days=2)
    check_up_to = 100
    for i in range(check_up_to):
        multiplied = start + i*interval
        summed = start
        for j in range(i):
            summed += interval
        print('i=%s, i*interval=%s, diff(multiplied-summed)=%s, multiplied=%s, summed=%s' %
              (i, i*interval, multiplied-summed, multiplied, summed))
        assert multiplied == summed

踪迹:

i*interval=relativedelta(), diff(multiplied-summed)=0:00:00, multiplied=2019-01-01 00:00:00, summed=2019-01-01 00:00:00
i=1, i*interval=relativedelta(months=+1, days=+2), diff(multiplied-summed)=0:00:00, multiplied=2019-02-03 00:00:00, summed=2019-02-03 00:00:00
i=2, i*interval=relativedelta(months=+2, days=+4), diff(multiplied-summed)=0:00:00, multiplied=2019-03-05 00:00:00, summed=2019-03-05 00:00:00
i=3, i*interval=relativedelta(months=+3, days=+6), diff(multiplied-summed)=0:00:00, multiplied=2019-04-07 00:00:00, summed=2019-04-07 00:00:00
i=4, i*interval=relativedelta(months=+4, days=+8), diff(multiplied-summed)=0:00:00, multiplied=2019-05-09 00:00:00, summed=2019-05-09 00:00:00
i=5, i*interval=relativedelta(months=+5, days=+10), diff(multiplied-summed)=0:00:00, multiplied=2019-06-11 00:00:00, summed=2019-06-11 00:00:00
i=6, i*interval=relativedelta(months=+6, days=+12), diff(multiplied-summed)=0:00:00, multiplied=2019-07-13 00:00:00, summed=2019-07-13 00:00:00
i=7, i*interval=relativedelta(months=+7, days=+14), diff(multiplied-summed)=0:00:00, multiplied=2019-08-15 00:00:00, summed=2019-08-15 00:00:00
i=8, i*interval=relativedelta(months=+8, days=+16), diff(multiplied-summed)=0:00:00, multiplied=2019-09-17 00:00:00, summed=2019-09-17 00:00:00
i=9, i*interval=relativedelta(months=+9, days=+18), diff(multiplied-summed)=0:00:00, multiplied=2019-10-19 00:00:00, summed=2019-10-19 00:00:00
i=10, i*interval=relativedelta(months=+10, days=+20), diff(multiplied-summed)=0:00:00, multiplied=2019-11-21 00:00:00, summed=2019-11-21 00:00:00
i=11, i*interval=relativedelta(months=+11, days=+22), diff(multiplied-summed)=0:00:00, multiplied=2019-12-23 00:00:00, summed=2019-12-23 00:00:00
i=12, i*interval=relativedelta(years=+1, days=+24), diff(multiplied-summed)=0:00:00, multiplied=2020-01-25 00:00:00, summed=2020-01-25 00:00:00
i=13, i*interval=relativedelta(years=+1, months=+1, days=+26), diff(multiplied-summed)=0:00:00, multiplied=2020-02-27 00:00:00, summed=2020-02-27 00:00:00
i=14, i*interval=relativedelta(years=+1, months=+2, days=+28), diff(multiplied-summed)=0:00:00, multiplied=2020-03-29 00:00:00, summed=2020-03-29 00:00:00
i=15, i*interval=relativedelta(years=+1, months=+3, days=+30), diff(multiplied-summed)=0:00:00, multiplied=2020-05-01 00:00:00, summed=2020-05-01 00:00:00
i=16, i*interval=relativedelta(years=+1, months=+4, days=+32), diff(multiplied-summed)=-1 day, 0:00:00, multiplied=2020-06-02 00:00:00, summed=2020-06-03 00:00:00

datetime.datetime(2020, 6, 2, 0, 0, 0) != datetime.datetime(2020, 6, 3, 0, 0, 0)

Expected :datetime.datetime(2020, 6, 3, 0, 0, 0)
Actual   :datetime.datetime(2020, 6, 2, 0, 0, 0)

版本: Python 3.6 python-dateutil == 2.8.0

1 个答案:

答案 0 :(得分:1)

让我以一种更简单的方式来举例说明:

start = datetime(year=2018, month=3, day=29)
interval = relativedelta(months=1, days=2)
d1 = start + interval * 2            # 2018-06-02
d2 = start + interval + interval     # 2018-06-03
print(d1, d2)

所以我什至不认为这是一个库错误:只要在头脑中遵循相同的计算,便会发现它们有意义。