我需要在添加N
(int)interval
s(用相对delta表示,因为它可以是月或年,也可以以秒或日期表示)后计算deadline
(日期时间)。我可以简单地通过将interval
乘以N
并将其求start_date
(日期时间)来做到这一点。同时,我需要分多个步骤完成,例如计算第 5 个截止日期、第 6 个截止日期......,所以我只需将interval
添加到start_date
N
次。 在某些情况下,这两种方法提供不同的结果。
假设start_date
= 日期时间(年 = 2019, 月=1, 日=2),interval
= 相对增量(月=1, 天=2),N
= 16。 从一个角度来看,这两种天蛾都是正确的,因为interval*16
=相对增量(年=+1,月=+4,天=+32),start_date+16*interval
=2019-01-01 + 1年+4个月+32天=2020/05/1+32天=2020-06-02(因为5月有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)
版本: 蟒蛇 3.6 python-dateutil==2.8.0
让我用更简单的方式举你的例子:
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)
所以我什至不认为这是一个库错误:只需在心理上遵循相同的计算,看看它们是否有意义。