在Python中如何添加年份

18

如果我在程序中想加100年,为什么显示的日期不正确?

import datetime
stringDate= "January 10, 1920"
dateObject= datetime.datetime.strptime(stringDate, "%B %d, %Y")
endDate= dateObject+datetime.timedelta(days=100*365)
print dateObject.date()
print endDate.date()

5
因为一年的长度不都是确切的365天? - jonrsharpe
4个回答

20

一年中的秒数不是固定的你认为一年有多少天?再去思考吧。

如果要进行周期(日历)运算,可以使用dateutil.relativedelta

#!/usr/bin/env python
from datetime import date
from dateutil.relativedelta import relativedelta # $ pip install python-dateutil

print(date(1920, 1, 10) + relativedelta(years=+100))
# -> 2020-01-10
为了理解为什么 d.replace(year=d.year + 100) 会失败,请考虑以下内容:
print(date(2000, 2, 29) + relativedelta(years=+100))
2100-02-28

请注意2100不是闰年,而2000是闰年。

如果您只想添加年份单位,则可以仅使用stdlib实现:

from calendar import isleap

def add_years(d, years):
    new_year = d.year + years
    try:
        return d.replace(year=new_year)
    except ValueError:
        if (d.month == 2 and d.day == 29 and # leap day
            isleap(d.year) and not isleap(new_year)):
            return d.replace(year=new_year, day=28)
        raise

例子:

from datetime import date

print(add_years(date(1920, 1, 10), 100))
# -> 2020-01-10
print(add_years(date(2000, 2, 29), 100))
# -> 2100-02-28
print(add_years(date(2000, 2, 29), 4))
# -> 2004-02-29

@amunnelly 这不是打字错误,而是为了可读性(突出操作符的符号)。 - jfs
@jfs 你说得对。我刚刚才注意到+号在哪一边。抱歉,今天早上我有点迟钝。我会删除原始评论。 - amunnelly
@jfs 您的前两个链接分别指向已删除的问题和需要付费访问的网站。 - ekhumoro
@ekhumoro:就像我说的:“它们提供背景信息--如果你看不到它们,就忽略它们。”而且你是对的:我应该说“最受赞同的”,而不是“被接受的”。我在你链接的答案中没有看到“相同”的解决方案(例如,我的答案包含一个仅使用stdlib的示例)。 - jfs
1
@jfs,我不知道你所说的“人身攻击”是什么意思。如果你的意图是为了造福社区,那么你的行为毫无意义。让其他用户自己决定他们想使用哪些答案。被删除的内容显然是你的答案的一部分,因为你直接链接到它。 - ekhumoro
显示剩余4条评论

15

你不能简单地将100 * 365天相加,因为该时间段中有366天的闰年。在你的100年中,你会少25天。

最好在这里使用 datetime.replace()方法

endDate = dateObject.replace(year=dateObject.year + 100)

在闰年的2月29日,即使根据您添加的年数来计算日期,您最终得到的日期可能是无效的,因此这种计算方法仍然有失败风险。在这种情况下,您可以倒回到2月28日,或使用3月31日作为替代日期;处理引发的异常并转而使用您选择的替代日期:

years = 100
try:
    endDate = dateObject.replace(year=dateObject.year + years)
except ValueError::
    # Leap day in a leap year, move date to February 28th
    endDate = dateObject.replace(year=dateObject.year + years, day=28)

演示:

>>> import datetime
>>> dateObject = datetime.datetime(1920, 1, 10, 0, 0)
>>> dateObject.replace(year=dateObject.year + 100)
datetime.datetime(2020, 1, 10, 0, 0)

1

man 3 mktime

任何做过 C 的人都知道答案。

mktime 会自动将溢出的值加到下一个更大的单位上。你只需要将其转换回日期时间即可。

例如,你可以输入 2019-07-40,它会被转换为 2019-08-09。

>>> datetime.fromtimestamp(mktime((2019, 7, 40, 0, 0, 0, 0, 0, 0)))
datetime.datetime(2019, 8, 9, 0, 0)

或者将2019-03-(-1)转换为2019-02-27:

>>> datetime.fromtimestamp(mktime((2019, 3, -1, 0, 0, 0, 0, 0, 0)))
datetime.datetime(2019, 2, 27, 0, 0)

所以你只需要拿出旧日期并加上你想要的任何内容:

now = datetime.datetime.now()
hundred_days_later = datetime.datetime.fromtimestamp(mktime((now.year, now.month, now.day + 100, now.hour, now.minute, now.second, 0, 0, 0)))

0
在过去的5年中,我一直使用pandas库中的 TimestampTimedelta 处理与日期有关的所有事务。
例如,要将3年添加到任何字符串格式的日期:
date = "2003-07-01"
date_start = Timestamp(date)
date_end = Timestamp(date_start.year+3, date_start.month, date_start.day)
date_end
# Out:
Timestamp('2006-07-01 00:00:00')

若要将日期增加40天,请使用Timedelta(它不支持年份,否则我们可以在最后一个问题中使用它):

date_end = date_start + Timedelta(40, unit="days")
date_end
# Out:
Timestamp('2003-08-10 00:00:00')

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接