4

私は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(2012, 10, 31, 0, 0)

終了日は現時点のものです。

私が使用する場合:

disclosure_dates = [dt for dt in rrule(MONTHLY, dtstart=disclosure_start_date, until=disclosure_end_date)]

1 か月おきまたは 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)]

何が間違っているのかわかりません。誰かがここで間違いを指摘できますか?

4

2 に答える 2

8

datetime.datetime(2012, 10, 31, 0, 0)あなたが直面している問題は、それがその月の 31 日であり、すべての月に 31 日があるわけではないという事実から来ています。モジュールは RFC 2445 の実装であるため、rruleRFC 3.3.10 によると:

繰り返しルールは、無効な日付 (例: 2 月 30 日) または存在しない現地時間 (例: 現地時間が午前 1:00 に 1 時間進む日の午前 1:30) の繰り返しインスタンスを生成する場合があります。そのような繰り返しインスタンスは無視しなければならず、繰り返しセットの一部として数えてはなりません。

月の 31 日を生成する月次ルールがあるため、30 日以下の月はすべてスキップされます。このバグ レポートdateutil、この問題についてで見ることができます。

月の最後の日だけが必要な場合は、次の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)]

残念ながら、必要な場合のみ月末にフォールバックする単純な RRULE を生成する RFC 準拠の方法はないと思います (たとえば、1 月 30 日に何をしますか? フォールバックが必要です)。 2月の場合、 bymonthday=-22月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です

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
于 2016-07-24T18:21:39.267 に答える