月の初日は、翌月の初日と同様に簡単に作成できます。それらを入手したら、残りはさらに簡単です。OPが指摘しているように、このcalendar.monthrange
関数は、月の最後の日を取得するための最も読みやすい方法を提供します。
>>> from datetime import date, year
>>> import calendar
>>> def first_day(dt):
... # Simply copy year and month into new date instance
... return date(dt.year, dt.month, 1)
...
>>> def last_day(dt):
... days_in_month = calendar.monthrange(dt.year, dt.month)[1]
... return date(dt.year, dt.month, days_in_month)
...
>>> nth_day = 32
>>> day_of_year = date(2012, 1, 1) + timedelta(days=nth_day - 1)
>>> day_of_year
datetime.date(2012, 2, 1)
>>> first_day(day_of_year), last_day(day_of_year)
(datetime.date(2012, 2, 1), datetime.date(2012, 2, 29))
>>> day_of_year - first_day(day_of_year), last_day(day_of_year) - day_of_year
(datetime.timedelta(0), datetime.timedelta(28))
これらの手法を1つの機能に組み合わせるには:
def delta_to_start_and_end(year, day_of_year):
dt = date(year, 1, 1) + timedelta(days=(day_of_year - 1))
def first_day(dt):
return date(dt.year, dt.month, 1)
def last_day(dt):
days_in_month = calendar.monthrange(dt.year, dt.month)[1]
return date(dt.year, dt.month, days_in_month)
return (dt - first_day(dt)).days, (last_day(dt) - dt).days
出力:
>>> delta_to_start_and_end(2012, 32)
(0, 28)
>>> delta_to_start_and_end(2011, 32)
(0, 27)
>>> delta_to_start_and_end(2012, 34)
(2, 26)
>>> delta_to_start_and_end(2012, 364)
(28, 2)
1
これらの2つの値のそれぞれに追加するかどうかはわかりません。現在、月の最初の日(最初の例)は0
最初の値として、(月の日数-1)は2番目の値として表示されます。これは、これらのポイントからの日数の差であるためです。これらが必要な場合+ 1
は、関数の最後の行に2回追加するのは簡単です。delta_to_start_and_end
歴史的なメモとして、この回答の以前のバージョンでは、カレンダーモジュールなしで月の最後の日を計算するために別の方法を使用していました。
def last_day(dt):
rest, month = divmod(dt.month, 12)
return date(dt.year + rest, month + 1, 1) - timedelta(days=1)
この関数は、divmod
組み込み関数を使用して、「現在の月は12月」のエッジケースを処理します。その場合、翌月はそうではありません13
が1
、年も1つ増やす必要があります。数値を「開始」にロールバックすることは数値の絶対値ですが、divmod
関数は除数も提供します。これは1
、現在の月がである場合に発生します12
。これにより、年をいつ増やすかを示す便利な指標が得られます。