Python:查找从今天开始两个月并且从星期一开始的日期

Python: Find date beginning two months prior to today AND start on a Monday

所以我是 python 的初学者,并且一直在使用 datetime、time 和 timedelta 库。我正在尝试创建一段代码,从今天(无论今天是什么时候)开始给我大约两个月前 (exact_two_months_date) 的日期。要注意的是,我想找到大约那个日期。两个月前并在那个星期的星期一开始实际的 start_date。所以从理论上讲,实际开始日期不会恰好是两个月前。从今天开始就是两个月前的周一开始的一周

Example pseudocode:
    today = '20150425' ## '%Y%m%d' ... Saturday
    exact_two_months_date = '20150225' ## EXACTLY two months ago ... Wednesday
    start_date = '20150223' ## this is the Monday of that week two months ago

那么如何找到上面的'start_date'呢?如果恰好两个月前的那一天是周六或周日开始的,那么我只想去下周一。希望这很清楚并且有意义......一旦我找到开始日期,我想每天(仅工作日)增加到 'today'。
感谢任何反馈,谢谢。

老实说,我发现与 datetimes 一起工作是我必须经常做的最困难的事情,而且我犯了很多错误,所以我将完成这个并展示一些我经常遇到的失败。开始了。

两个约束条件:1) 两个月前的日期,2) 那一周的星期一

两个月前的日期

好的,所以 Python 的 datetime 库有一个名为 replace 的有用方法,它似乎对这里有帮助:

>>> import datetime
>>> now = datetime.date.today()
>>> today
datetime.date(2015, 4, 25)
>>> today.month
4
>>> two_months_ago = today.replace(month=today.month-2)
>>> two_months_ago
datetime.date(2015, 2, 25)
>>> two_months_ago.month
2

但是等等:负数呢?那行不通:

>>> older = datetime.date(2015, 01, 01)
>>> older.replace(month=older.month-2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: month must be in 1..12

所以有两种解决方案:

1) 我可以构建一个向前或向后循环的 1-12 范围,或者

2) 要找到两个月前的日期,我只需将日期的 day 部分替换为我所在月份的 1st 日,然后返回 1 天上个月然后然后用我想要的那一天替换上个月的那一天。

(如果你仔细想想,你会发现,如果我在一个月的第 31 天着陆,而且天数比这少,那么这些中的任何一个都可能会出现错误,例如。这是 [=13 的部分原因=]很难。)

def previous_month(date):
    current_day = date.day
    first_day = date.replace(day=1)
    last_day_prev_month = first_day - datetime.timedelta(days=1)
    prev_month_day = last_day_prev_month.replace(day=current_day)
    return prev_month_day

>>> today = datetime.date.today()
>>> older = previous_month(today)
>>> older
datetime.date(2015, 3, 25)

好吧,假设我们已经很接近了,我们需要进行一些错误检查,以确保我们想要的日期是我们到达的月份内的有效日期。最终,问题是"two months ago" 比我们大声说出来时所想的要多得多。

接下来,我们将解决第二个问题:如何到达该周的星期一?

好吧,datetime 对象有一个工作日方法,所以这部分应该不会太难 here's a nice SO answer on how to do that

简单的版本是:使用工作日整数的差异来计算返回多少天,然后使用 datetime.timedelta(days=days_difference)

要点:与 datetime 一起工作可能很困难。

使用 python-dateutil
计算日期 如果可以选择依赖第三方包,那么 python-dateutil 提供了一种方便的方法来计算日期。

浏览 ☞ relativedelta to see the wealth of supported parameters. The more calculations a package needs to do with dates, the more a helper module like dateutil justifies its dependency. For more inspiration on what it has to offer see the ☞ examples page 的文档。

快速运行-通过:

>>> import datetime
>>> from dateutil.relativedelta import relativedelta

>>> today = datetime.date.today()
>>> two_m_ago = today - relativedelta(months=2)
>>> # print two_m_ago ~> datetime.date(2015, 2, 25)

>>> monday = two_m_ago - datetime.timedelta(days=two_m_ago.weekday())
>>> # print monday ~> datetime.date(2015, 2, 23)

通过 weekday()
获取星期一 一旦我们在变量 two_m_ago 中有了两个月前的日期,我们就从中减去 weekday() 的索引。该索引在星期一为 0,在星期日一直到 6。如果 two_m_ago 已经是星期一,则减去 0 不会导致任何更改。

这样的事情对你有用吗?

import datetime

today = datetime.date.today()
delta = datetime.timedelta(days=60) # ~ 2 months

thatDay = today - delta
# subtract weekdays to get monday
thatMonday = thatDay - datetime.timedelta(days=thatDay.weekday()) 

Python 中的日期操作非常复杂。使用 arrow 包大大简化了这些操作,您将节省大量时间。

首先安装它

pip install arrow

现在你的问题:

import arrow

# get local current time
now = arrow.now('local')

# move 2 months back
old = now.replace(months=-2)

# what day of the week was that?
dow = old.isoweekday()

# reset old to Monday, for instance at 9:32 in the morning (this is just an example, just to show case)
old = old.replace(days=-dow, hour=9, minute=32, second=0)

print('now is {now}, we went back to {old}'.format(now=now.isoformat(), old=old.isoformat()))

输出:

now is 2015-04-25T20:37:38.174000+02:00, we went back to 2015-02-22T09:32:00.174000+01:00

请注意,各种格式、时区等现在都是透明的,您只需要依赖一个包。