dateutils rrule returns 相隔 2 个月的日期
dateutils rrule returns dates that 2 months apart
我是 Python 和 dateutil
模块的新手。我传递以下参数:
disclosure_start_date = resultsDict['fd_disclosure_start_date']
disclosure_end_date = datetime.datetime.now()
disclosure_dates = [dt for dt in rrule(MONTHLY, dtstart=disclosure_start_date, until=disclosure_end_date)]
这里disclosure_start_date = 2012-10-31 00:00:00
转换为datetime是datetime.datetime(2012, 10, 31, 0, 0)
截止日期为现在。
当我使用:
disclosure_dates = [dt for dt in rrule(MONTHLY, dtstart=disclosure_start_date, until=disclosure_end_date)]
我每隔一个月或相隔 2 个月获取日期。结果是:
>>> list(disclosure_dates)
[datetime.datetime(2012, 10, 31, 0, 0),
datetime.datetime(2012, 12, 31, 0, 0),
datetime.datetime(2013, 1, 31, 0, 0),
datetime.datetime(2013, 3, 31, 0, 0),
datetime.datetime(2013, 5, 31, 0, 0),
datetime.datetime(2013, 7, 31, 0, 0),
datetime.datetime(2013, 8, 31, 0, 0),
datetime.datetime(2013, 10, 31, 0, 0),
datetime.datetime(2013, 12, 31, 0, 0),
datetime.datetime(2014, 1, 31, 0, 0),
datetime.datetime(2014, 3, 31, 0, 0),
datetime.datetime(2014, 5, 31, 0, 0),
datetime.datetime(2014, 7, 31, 0, 0),
datetime.datetime(2014, 8, 31, 0, 0),
datetime.datetime(2014, 10, 31, 0, 0),
datetime.datetime(2014, 12, 31, 0, 0),
datetime.datetime(2015, 1, 31, 0, 0),
datetime.datetime(2015, 3, 31, 0, 0),
datetime.datetime(2015, 5, 31, 0, 0),
datetime.datetime(2015, 7, 31, 0, 0),
datetime.datetime(2015, 8, 31, 0, 0),
datetime.datetime(2015, 10, 31, 0, 0),
datetime.datetime(2015, 12, 31, 0, 0),
datetime.datetime(2016, 1, 31, 0, 0),
datetime.datetime(2016, 3, 31, 0, 0),
datetime.datetime(2016, 5, 31, 0, 0)]
我不确定我做错了什么。有人可以指出这里的错误吗?
您遇到的问题是因为 datetime.datetime(2012, 10, 31, 0, 0)
是该月的 31 号,并非所有月份都有 31 号。由于 rrule
模块是 RFC 2445 的实现。根据 RFC 3.3.10:
Recurrence rules may generate recurrence instances with an invalid date (e.g., February 30) or nonexistent local time (e.g., 1:30 AM on a day where the local time is moved forward by an hour at 1:00 AM). Such recurrence instances MUST be ignored and MUST NOT be counted as part of the recurrence set.
由于您有一个生成每月 31 日的月度规则,它会跳过所有天数不超过 30 天的月份。您可以在 dateutil
中查看有关此问题的 this bug report。
如果你只想要一个月的最后一天,你应该使用 bymonthday=-1
参数:
from dateutil.rrule import rrule, MONTHLY
from datetime import datetime
disclosure_start_date = datetime(2012, 10, 31, 0, 0)
rr = rrule(freq=MONTHLY, dtstart=disclosure_start_date, bymonthday=-1)
# >>>rr.between(datetime(2013, 1, 1), datetime(2013, 5, 1))
# [datetime.datetime(2013, 1, 31, 0, 0),
# datetime.datetime(2013, 2, 28, 0, 0),
# datetime.datetime(2013, 3, 31, 0, 0),
# datetime.datetime(2013, 4, 30, 0, 0)]
不幸的是,我不认为有一种符合 RFC 标准的方法来生成一个简单的 RRULE,当且仅当它是必要的时候(例如,你对一月做什么) 30 日 - 您需要为 2 月回退,但您不想使用 bymonthday=-2
,因为那样会给您 2 月 27 日等)。
或者,对于像这样的简单月度规则,更好的选择可能是只使用 relativedelta
, 会回落到月末:
from dateutil.relativedelta import relativedelta
from datetime import datetime
def disclosure_dates(dtstart, rd, dtend=None):
ii = 0
while True:
cdate = dtstart + ii*rd
ii += 1
yield cdate
if dtend is not None and cdate >= dtend:
break
dtstart = datetime(2013, 1, 31, 0, 0)
rd = relativedelta(months=1)
rr = disclosure_dates(dtstart, rd, dtend=datetime(2013, 5, 1))
# >>> list(rr)
# [datetime.datetime(2013, 1, 31, 0, 0),
# datetime.datetime(2013, 2, 28, 0, 0),
# datetime.datetime(2013, 3, 31, 0, 0),
# datetime.datetime(2013, 4, 30, 0, 0),
# datetime.datetime(2013, 5, 31, 0, 0)]
请注意,我专门使用了 cdate = dtstart + ii * rd
,你 而不是 只想保留一个 "running tally",因为这会将计数固定到最短的月份看过:
dt_base = datetime(2013, 1, 31)
dt = dt_base
for ii in range(5):
cdt = dt_base + ii*rd
print('{} | {}'.format(dt, cdt))
dt += rd
结果:
2013-01-31 00:00:00 | 2013-01-31 00:00:00
2013-02-28 00:00:00 | 2013-02-28 00:00:00
2013-03-28 00:00:00 | 2013-03-31 00:00:00
2013-04-28 00:00:00 | 2013-04-30 00:00:00
2013-05-28 00:00:00 | 2013-05-31 00:00:00
"datetime.datetime(2022, 1, 3, 0, 0)"
我是 Python 和 dateutil
模块的新手。我传递以下参数:
disclosure_start_date = resultsDict['fd_disclosure_start_date']
disclosure_end_date = datetime.datetime.now()
disclosure_dates = [dt for dt in rrule(MONTHLY, dtstart=disclosure_start_date, until=disclosure_end_date)]
这里disclosure_start_date = 2012-10-31 00:00:00
转换为datetime是datetime.datetime(2012, 10, 31, 0, 0)
截止日期为现在。
当我使用:
disclosure_dates = [dt for dt in rrule(MONTHLY, dtstart=disclosure_start_date, until=disclosure_end_date)]
我每隔一个月或相隔 2 个月获取日期。结果是:
>>> list(disclosure_dates)
[datetime.datetime(2012, 10, 31, 0, 0),
datetime.datetime(2012, 12, 31, 0, 0),
datetime.datetime(2013, 1, 31, 0, 0),
datetime.datetime(2013, 3, 31, 0, 0),
datetime.datetime(2013, 5, 31, 0, 0),
datetime.datetime(2013, 7, 31, 0, 0),
datetime.datetime(2013, 8, 31, 0, 0),
datetime.datetime(2013, 10, 31, 0, 0),
datetime.datetime(2013, 12, 31, 0, 0),
datetime.datetime(2014, 1, 31, 0, 0),
datetime.datetime(2014, 3, 31, 0, 0),
datetime.datetime(2014, 5, 31, 0, 0),
datetime.datetime(2014, 7, 31, 0, 0),
datetime.datetime(2014, 8, 31, 0, 0),
datetime.datetime(2014, 10, 31, 0, 0),
datetime.datetime(2014, 12, 31, 0, 0),
datetime.datetime(2015, 1, 31, 0, 0),
datetime.datetime(2015, 3, 31, 0, 0),
datetime.datetime(2015, 5, 31, 0, 0),
datetime.datetime(2015, 7, 31, 0, 0),
datetime.datetime(2015, 8, 31, 0, 0),
datetime.datetime(2015, 10, 31, 0, 0),
datetime.datetime(2015, 12, 31, 0, 0),
datetime.datetime(2016, 1, 31, 0, 0),
datetime.datetime(2016, 3, 31, 0, 0),
datetime.datetime(2016, 5, 31, 0, 0)]
我不确定我做错了什么。有人可以指出这里的错误吗?
您遇到的问题是因为 datetime.datetime(2012, 10, 31, 0, 0)
是该月的 31 号,并非所有月份都有 31 号。由于 rrule
模块是 RFC 2445 的实现。根据 RFC 3.3.10:
Recurrence rules may generate recurrence instances with an invalid date (e.g., February 30) or nonexistent local time (e.g., 1:30 AM on a day where the local time is moved forward by an hour at 1:00 AM). Such recurrence instances MUST be ignored and MUST NOT be counted as part of the recurrence set.
由于您有一个生成每月 31 日的月度规则,它会跳过所有天数不超过 30 天的月份。您可以在 dateutil
中查看有关此问题的 this bug report。
如果你只想要一个月的最后一天,你应该使用 bymonthday=-1
参数:
from dateutil.rrule import rrule, MONTHLY
from datetime import datetime
disclosure_start_date = datetime(2012, 10, 31, 0, 0)
rr = rrule(freq=MONTHLY, dtstart=disclosure_start_date, bymonthday=-1)
# >>>rr.between(datetime(2013, 1, 1), datetime(2013, 5, 1))
# [datetime.datetime(2013, 1, 31, 0, 0),
# datetime.datetime(2013, 2, 28, 0, 0),
# datetime.datetime(2013, 3, 31, 0, 0),
# datetime.datetime(2013, 4, 30, 0, 0)]
不幸的是,我不认为有一种符合 RFC 标准的方法来生成一个简单的 RRULE,当且仅当它是必要的时候(例如,你对一月做什么) 30 日 - 您需要为 2 月回退,但您不想使用 bymonthday=-2
,因为那样会给您 2 月 27 日等)。
或者,对于像这样的简单月度规则,更好的选择可能是只使用 relativedelta
, 会回落到月末:
from dateutil.relativedelta import relativedelta
from datetime import datetime
def disclosure_dates(dtstart, rd, dtend=None):
ii = 0
while True:
cdate = dtstart + ii*rd
ii += 1
yield cdate
if dtend is not None and cdate >= dtend:
break
dtstart = datetime(2013, 1, 31, 0, 0)
rd = relativedelta(months=1)
rr = disclosure_dates(dtstart, rd, dtend=datetime(2013, 5, 1))
# >>> list(rr)
# [datetime.datetime(2013, 1, 31, 0, 0),
# datetime.datetime(2013, 2, 28, 0, 0),
# datetime.datetime(2013, 3, 31, 0, 0),
# datetime.datetime(2013, 4, 30, 0, 0),
# datetime.datetime(2013, 5, 31, 0, 0)]
请注意,我专门使用了 cdate = dtstart + ii * rd
,你 而不是 只想保留一个 "running tally",因为这会将计数固定到最短的月份看过:
dt_base = datetime(2013, 1, 31)
dt = dt_base
for ii in range(5):
cdt = dt_base + ii*rd
print('{} | {}'.format(dt, cdt))
dt += rd
结果:
2013-01-31 00:00:00 | 2013-01-31 00:00:00
2013-02-28 00:00:00 | 2013-02-28 00:00:00
2013-03-28 00:00:00 | 2013-03-31 00:00:00
2013-04-28 00:00:00 | 2013-04-30 00:00:00
2013-05-28 00:00:00 | 2013-05-31 00:00:00
"datetime.datetime(2022, 1, 3, 0, 0)"