从Python中的某个日期减去一个月的最简单方法是什么?

Bia*_*cki 79 python

如果只有timedelta在它的构造函数中有一个月参数.那么最简单的方法是什么?

编辑:我并没有像下面所指出的那样对此进行太多考虑.真的我想要的是上个月的任何一天,因为最终我只会抓住一年和一个月.因此,给定一个datetime对象,返回上个月的任何datetime对象的最简单方法是什么

amo*_*moe 156

您可以使用第三方dateutil模块(此处为 PyPI条目).

import datetime
import dateutil.relativedelta

d = datetime.datetime.strptime("2013-03-31", "%Y-%m-%d")
d2 = d - dateutil.relativedelta.relativedelta(months=1)
print d2
Run Code Online (Sandbox Code Playgroud)

输出:

2013-02-28 00:00:00
Run Code Online (Sandbox Code Playgroud)

  • @SiminJie:我认为使用 `months` 会产生 1 个月的差异。使用 `month` 会将月份设置为 1(例如一月),而不管输入的月份。 (3认同)
  • 我对 dateutil 中的参数 `month` 和 `months` 感到困惑。用参数“month”减去不起作用,但“months”起作用“In [23]: created_datetime__lt - relativedelta(months=1) Out[23]: datetime.datetime(2016, 11, 29, 0, 0, tzinfo= <StaticTzInfo 'Etc/GMT-8'>) 在 [24]: created_datetime__lt - relativedelta(month=1) Out[24]: datetime.datetime(2016, 1, 29, 0, 0, tzinfo=<StaticTzInfo 'Etc/ GMT-8'>)` (2认同)

Cor*_*ory 54

在原始问题编辑为"上个月的任何日期时间对象"之后,您可以通过从该月的第一天减去1天来轻松完成.

from datetime import datetime, timedelta

def a_day_in_previous_month(dt):
   return dt.replace(day=1) - timedelta(days=1)
Run Code Online (Sandbox Code Playgroud)

  • 你可以使用`dt.replace(day = 1) - timedelta(1)` (4认同)
  • 或`dt-timedelta(days = dt.day)` (2认同)

Dun*_*can 50

试试这个:

def monthdelta(date, delta):
    m, y = (date.month+delta) % 12, date.year + ((date.month)+delta-1) // 12
    if not m: m = 12
    d = min(date.day, [31,
        29 if y%4==0 and not y%400==0 else 28,31,30,31,30,31,31,30,31,30,31][m-1])
    return date.replace(day=d,month=m, year=y)

>>> for m in range(-12, 12):
    print(monthdelta(datetime.now(), m))


2009-08-06 16:12:27.823000
2009-09-06 16:12:27.855000
2009-10-06 16:12:27.870000
2009-11-06 16:12:27.870000
2009-12-06 16:12:27.870000
2010-01-06 16:12:27.870000
2010-02-06 16:12:27.870000
2010-03-06 16:12:27.886000
2010-04-06 16:12:27.886000
2010-05-06 16:12:27.886000
2010-06-06 16:12:27.886000
2010-07-06 16:12:27.886000
2010-08-06 16:12:27.901000
2010-09-06 16:12:27.901000
2010-10-06 16:12:27.901000
2010-11-06 16:12:27.901000
2010-12-06 16:12:27.901000
2011-01-06 16:12:27.917000
2011-02-06 16:12:27.917000
2011-03-06 16:12:27.917000
2011-04-06 16:12:27.917000
2011-05-06 16:12:27.917000
2011-06-06 16:12:27.933000
2011-07-06 16:12:27.933000
>>> monthdelta(datetime(2010,3,30), -1)
datetime.datetime(2010, 2, 28, 0, 0)
>>> monthdelta(datetime(2008,3,30), -1)
datetime.datetime(2008, 2, 29, 0, 0)
Run Code Online (Sandbox Code Playgroud)

编辑更正以处理当天.

编辑另请参阅拼图中的答案,该答案指出了一个更简单的计算d:

d = min(date.day, calendar.monthrange(y, m)[1])
Run Code Online (Sandbox Code Playgroud)


puz*_*ent 22

Duncan答案的变体(我没有足够的评论声誉),它使用calendar.monthrange来大大简化当月最后一天的计算:

import calendar
def monthdelta(date, delta):
    m, y = (date.month+delta) % 12, date.year + ((date.month)+delta-1) // 12
    if not m: m = 12
    d = min(date.day, calendar.monthrange(y, m)[1])
    return date.replace(day=d,month=m, year=y)
Run Code Online (Sandbox Code Playgroud)

有关使用Python 获取最后一天的月份信息的信息


Fra*_*nca 19

我认为简单的方法是使用 Pandas 中的 DateOffset,如下所示:

import pandas as pd
date_1 = pd.to_datetime("2013-03-31", format="%Y-%m-%d") - pd.DateOffset(months=1)
Run Code Online (Sandbox Code Playgroud)

结果将是一个 Timestamp 对象

  • 这是最直观的解决方案 (3认同)

Ale*_*lli 15

如果只有timedelta在它的构造函数中有一个月参数.那么最简单的方法是什么?

当你从3月30日的某个日期减去一个月时,你想要的结果是什么?这是增加或减少月份的问题:月份有不同的长度!在某些应用程序中,异常在这种情况下是合适的,在其他情况下"上个月的最后一天"可以使用(但这是真正疯狂的算术,当减去一个月然后添加一个月不是整体的无操作!) ,在其他人你还想要除了日期之外还有一些关于这个事实的迹象,例如,"我说的是2月28日,但如果它存在,我真的想要2月30日",所以增加或减去另一个月到这可以使事情再次正确(而后者显然需要一个自定义类来保存数据加上其他东西).

没有真正的解决方案可以容忍所有应用程序,并且您没有告诉我们您的特定应用程序对这个可怜操作的语义的需求,因此我们在这里提供的帮助不多.


Cor*_*son 9

A vectorized, pandas solution is very simple:

df['date'] - pd.DateOffset(months=1)


Leo*_*ael 7

如果您只想要上个月的任何一天,那么您可以做的最简单的事情是从当前日期中减去天数,这将得到上个月的最后一天。

例如,从任何日期开始:

>>> import datetime                                                                                                                                                                 
>>> today = datetime.date.today()                                                                                                                                                   
>>> today
datetime.date(2016, 5, 24)
Run Code Online (Sandbox Code Playgroud)

减去当前日期的天数,我们得到:

>>> last_day_previous_month = today - datetime.timedelta(days=today.day)
>>> last_day_previous_month
datetime.date(2016, 4, 30)
Run Code Online (Sandbox Code Playgroud)

这足以满足您对上个月任何一天的简化需求。

但是现在你有了它,你也可以得到一个月中的任何一天,包括你开始的同一天(即或多或少与减去一个月相同):

>>> same_day_last_month = last_day_previous_month.replace(day=today.day)
>>> same_day_last_month
datetime.date(2016, 4, 24)
Run Code Online (Sandbox Code Playgroud)

当然,您需要小心处理 30 天月份的 31 日或 2 月缺少的日子(并注意闰年),但这也很容易做到:

>>> a_date = datetime.date(2016, 3, 31)                                                                                                                                             
>>> last_day_previous_month = a_date - datetime.timedelta(days=a_date.day)
>>> a_date_minus_month = (
...     last_day_previous_month.replace(day=a_date.day)
...     if a_date.day < last_day_previous_month.day
...     else last_day_previous_month
... )
>>> a_date_minus_month
datetime.date(2016, 2, 29)
Run Code Online (Sandbox Code Playgroud)