Pythonで月初・月末(初日・最終日)、最終X曜日の日付を取得

Modified: | Tags: Python, 日時処理

Pythonで、月初・月末(月の初日・最終日)および最終X曜日(最終月曜日、最終金曜日など)の日付(年月日)を、datetime.datetimedatetime.dateとして取得する方法を説明する。

標準ライブラリのdatetimeモジュールおよびcalendarモジュールを使う。

本記事のサンプルコードでは、以下のようにdatetimeモジュールおよびcalendarモジュールをインポートしている。

import datetime
import calendar

月初(月の初日)の日付を取得

任意の日付(datetime, date)の月の初日

ある日付を指定してその月の初日の日付を返す関数は以下の通り。日にちの値をreplace()メソッドで1に置き換えているだけ。

日時(日付と時刻)を表すdatetime.datetimeも日付のみを表すdatetime.datereplace()メソッドを持っているので、引数に指定するのはどちらでもよい。

def get_first_date(dt):
    return dt.replace(day=1)

dt = datetime.datetime(2023, 8, 10, 10, 10, 10)
print(dt)
# 2023-08-10 10:10:10

print(get_first_date(dt))
# 2023-08-01 10:10:10

d = datetime.date(2023, 8, 10)
print(d)
# 2023-08-10

print(get_first_date(d))
# 2023-08-01

今の日時や今日の日付をdatetime.datetimenow()メソッドやdatetime.datetoday()メソッドで取得して引数とすることもできる。

print(datetime.date.today())
# 2023-10-10

print(get_first_date(datetime.date.today()))
# 2023-10-01

任意の年、月の初日

年、月を指定してその月の初日の日付を返す関数はもっと単純。関数にするまでもないかもしれない。

def get_first_date2(year, month):
    return datetime.date(year, month, 1)

print(get_first_date2(2023, 8))
# 2023-08-01

例はdatetime.dateを返すようにしているが、datetime.datetimeでも同様。datetime.datetime()で時刻を省略すると00:00:00となる。

月末(月の最終日)の日付を取得

月の日数(最終日の日)

月の最終日の日にちはその月の日数に等しい。ある月の日数はcalendar.monthrange()で取得できる。

calendar.monthrange()が返すのは月の初日の曜日を表す数値と日数のタプル。

print(calendar.monthrange(2023, 8))
# (1, 31)

print(calendar.monthrange(2023, 8)[1])
# 31

任意の日付(datetime, date)の月の最終日

あとは初日の場合と同様。日にちの値をreplace()メソッドで最終日に置き換えるだけ。

def get_last_date(dt):
    return dt.replace(day=calendar.monthrange(dt.year, dt.month)[1])

dt = datetime.datetime(2023, 8, 10, 10, 10, 10)
print(dt)
# 2023-08-10 10:10:10

print(get_last_date(dt))
# 2023-08-31 10:10:10

d = datetime.date(2023, 8, 10)
print(d)
# 2023-08-10

print(get_last_date(d))
# 2023-08-31

print(datetime.date.today())
# 2023-10-10

print(get_last_date(datetime.date.today()))
# 2023-10-31

任意の年、月の最終日

年、月を指定する場合は以下の通り。

def get_last_date2(year, month):
    return datetime.date(year, month, calendar.monthrange(year, month)[1])

print(get_last_date2(2023, 8))
# 2023-08-31

例はdatetime.dateを返すようにしているが、datetime.datetimeでも同様。

月の最終X曜日の日付を取得

最終X曜日の日にち

月の最終X曜日(最終月曜日、最終金曜日など)の日にちを算出する関数の例は以下の通り。あくまでも一例。もっとスマートな方法があるかもしれない。

第三引数dow(day of the week: 曜日)には月曜日0から日曜日6までの曜日を表す数値を指定する。

def get_day_of_last_week(year, month, dow):
    '''dow: Monday(0) - Sunday(6)'''
    n = calendar.monthrange(year, month)[1]
    l = range(n - 6, n + 1)
    w = calendar.weekday(year, month, l[0])
    w_l = [i % 7 for i in range(w, w + 7)]
    return l[w_l.index(dow)]

結果は以下の通り。カレンダーとともに示す。

print(calendar.month(2023, 8))
#     August 2023
# Mo Tu We Th Fr Sa Su
#     1  2  3  4  5  6
#  7  8  9 10 11 12 13
# 14 15 16 17 18 19 20
# 21 22 23 24 25 26 27
# 28 29 30 31
# 

print(get_day_of_last_week(2023, 8, 0))
# 28

print(get_day_of_last_week(2023, 8, 3))
# 31

print(get_day_of_last_week(2023, 8, 4))
# 25

なお、最終X曜日は第4X曜日か第5X曜日のいずれか。第nX曜日(第2月曜日など)の日付を取得したい場合は以下の記事を参照。

以下、関数の中身を簡単に説明する。

最終日の日にちをcalendar.monthrange()で取得して、最終週の日にちをrange()で表現。

year = 2023
month = 8
dow = 0

n = calendar.monthrange(year, month)[1]
print(n)
# 31

l = range(n - 6, n + 1)
print(list(l))
# [25, 26, 27, 28, 29, 30, 31]

最終週の曜日のリストを生成。

w = calendar.weekday(year, month, l[0])
print(w)
# 4

w_l = [i % 7 for i in range(w, w + 7)]
print(w_l)
# [4, 5, 6, 0, 1, 2, 3]

index()でターゲットの曜日が最終週の何番目かを取得し、さらに、その日にちを取得。

print(l[w_l.index(dow)])
# 28

任意の日付(datetime, date)の月の最終X曜日

任意の日付(datetime, date)から最終X曜日の日付を取得したい場合は、上で定義した関数を使って、初日や最終日と同様に処理すればよい。

def get_date_of_last_week(dt, dow):
    '''dow: Monday(0) - Sunday(6)'''
    return dt.replace(day=get_day_of_last_week(dt.year, dt.month, dow))

dt = datetime.datetime(2023, 8, 10, 10, 10, 10)
print(dt)
# 2023-08-10 10:10:10

print(get_date_of_last_week(dt, 0))
# 2023-08-28 10:10:10

print(get_date_of_last_week(dt, 3))
# 2023-08-31 10:10:10

d = datetime.date(2023, 8, 10)
print(d)
# 2023-08-10

print(get_date_of_last_week(d, 0))
# 2023-08-28

print(get_date_of_last_week(d, 3))
# 2023-08-31

任意の年、月の最終X曜日

年、月を指定する場合は以下の通り。

def get_date_of_last_week2(year, month, dow):
    '''dow: Monday(0) - Sunday(6)'''
    return datetime.date(year, month, get_day_of_last_week(year, month, dow))

print(get_date_of_last_week2(2023, 8, 0))
# 2023-08-28

例はdatetime.dateを返すようにしているが、datetime.datetimeでも同様。

関連カテゴリー

関連記事