Python:获取“三年前的今天”的日期和时间

104
在Python中,我如何获得“三年前今天”的日期时间对象?
更新:FWIW,我不特别关心准确性...即今天是2月29日,我不介意在我的答案中给出2月28日或3月1日。在这种情况下,简洁比可配置性更重要。

可能是重复的问题:如何创建一个等于15分钟前的DateTime? - Marc B
3
假设今天是3月1日,无论是否闰年,您都希望得到的是3月1日,对吗?我认为所有现有的答案在这方面都没有达到要求。 - Mark Ransom
几乎,但并非完全相同:15分钟和3年之间的区别是显著的。15分钟是固定不变的,而3年则不是。 - JasonFruit
@Jason 我同意你的看法,尽管从楼主的编辑来看,他似乎并不是特别关心这个问题,所以如果是这种情况,那就是一个重复问题。 - Davy8
4
这个网站真的需要一种方式,让社区能够覆盖当人们接受明显不正确的答案时。3*365天并不等于3年,而正确的答案就在那里。 - Glenn Maynard
@Glenn Maynard - 你可以编辑标题。因为他并不是真的想要三年前的内容。 - Chris Dutrow
8个回答

201

如果您需要精确计算相对日期,请使用dateutil模块

from datetime import datetime
from dateutil.relativedelta import relativedelta

three_yrs_ago = datetime.now() - relativedelta(years=3)

1
我只需要针对日期怎么做? - DanielBell99

132
import datetime
datetime.datetime.now() - datetime.timedelta(days=3*365)

51
AP257说:“我不是非常关心准确性。” 我的理解是,“我不关心闰年”。 - Fábio Diniz
8
@Diniz:你把它理解成“我想要错”。做正确的事情非常容易,做错了很愚蠢,如果正确答案可用,接受错误答案就很奇怪。 - Glenn Maynard
7
当问者明确表示相反的意见时,给出一份不太简洁但更准确的答案是否正确? - Fábio Diniz
8
为了简单起见,也许原帖仅仅想要一个关于如何一般性地做类似事情的示例。+1 - Chris Dutrow
谢谢你的简洁。我也不在乎准确性。我实际上只是想找到两天之间的差异。 - VertigoRay
显示剩余2条评论

32

减去365*3天是错误的,当然——你大部分时间都会跨越一个闰年。

dt = datetime.now()
dt = dt.replace(year=dt.year-3)
# datetime.datetime(2008, 3, 1, 13, 2, 36, 274276)

ED:为了解决闰年问题,

def subtract_years(dt, years):
    try:
        dt = dt.replace(year=dt.year-years)
    except ValueError:
        dt = dt.replace(year=dt.year-years, day=dt.day-1)
    return dt

1
现在你还有另一个问题:datetime.datetime(2008,2,29).replace(year=2005) -> ValueError。我想捕获这个错误并减去一个额外的天数仍然更加准确。 - Jochen Ritzel
我总是忘记 replace。它比我的解决方案更简单。 - Mark Ransom
@Mark:我一开始也是这样做的;我最初也做了你所做的。然而,该网站似乎在编辑历史中错放了那个版本。 - Glenn Maynard
2100年之后会发生什么? - PartialOrder

4
def add_years(dt, years):
    try:
        result = datetime.datetime(dt.year + years, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond, dt.tzinfo)
    except ValueError:
        result = datetime.datetime(dt.year + years, dt.month, dt.day - 1, dt.hour, dt.minute, dt.second, dt.microsecond, dt.tzinfo)
    return result

>>> add_years(datetime.datetime.now(), -3)
datetime.datetime(2008, 3, 1, 12, 2, 35, 22000)
>>> add_years(datetime.datetime(2008, 2, 29), -3)
datetime.datetime(2005, 2, 28, 0, 0)

1
这可以解决闰年和非闰年的特殊情况。因为如果日期是2月29日(即month=2, day=29),非闰年将抛出值错误,因为没有2月29日,2月的最后一天是28日,因此在try-except块中对日期进行-1操作即可。
from datetime import datetime

last_year = datetime.today().year - 1
month = datetime.today().month
day = datetime.today().day

try:
    # try returning same date last year
    last_year_date = datetime.strptime(f"{last_year}-{month}-{day}",'%Y-%m-%d').date()
except ValueError: 
    # incase of error due to leap year, return date - 1 in last year
    last_year_date = datetime.strptime(f"{last_year}-{month}-{day-1}",'%Y-%m-%d').date()

print(last_year_date)

-1
In [3]: import datetime as dt

In [4]: today=dt.date.today()

In [5]: three_years_ago=today-dt.timedelta(days=3*365)

In [6]: three_years_ago
Out[6]: datetime.date(2008, 3, 1)

它不考虑闰年。 - CodeTalker

-1

我曾试图只使用标准库来解决问题,并且这个方法对我奏效了。请注意,如果没有检查,大多数年份的2月29日将会给你一个ValueError。在其他所有日期,它将会给出“三年前今天”的日期。

today = date.today()
day = 28 if today.month == 2 and today.day == 29 else today.day
three_years_ago = date(today.year - 3, today.month, day)

-3
为什么不在替换年份前先检查是否是闰年呢?这不需要任何额外的包或try:Except。
def years_ago(dt, years):
    if dt.month == 2 and dt.day == 29:
        dt = dt.replace(day=28)

    return dt.replace(year=dt.year - years)

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