■概要
月、日、および曜日を指定して、直近同じ月日と曜日の年をyyyy-mm-dd(曜日)形式で表示する。
また、指定した月日と曜日が処理日と同じ場合は、処理日の曜日も表示する。
・概要図
▼ディレクトリ構成
実装するディレクトリ構成は以下の通り。

※以下の記述について、単体テストファイルについては、割愛する(GitHub参照)。
■フローチャート
前述の「▼ディレクトリ構成」にて提示したファイル名に対する、各処理のフローチャートを以下に示す。
※「get_next_and_last_day_const.py」については、定数のみのためフローチャートは割愛する(後述の「■サンプルコード」参照)。
▼main.py
・メイン処理
▼get_next_and_last_day_util.py
・曜日判定処理
・日付フォーマット処理
・結果出力処理
・対象日付検索処理
・閏年取得処理
■サンプルコード
・main.py
from datetime import datetime
from util.get_next_and_last_day_util import is_week_format, date_formatter, \
search_day, print_day
def main(month: int, day: int, weekday: str) -> None:
# 処理日を取得
dt_now = datetime.now()
# 閏年フラグ初期化
is_leap_year = False
# デフォルトの年は処理日付の年
dt_default_year = dt_now.year
# 2/29なら閏年判定
if month == 2 and day == 29:
is_leap_year = True
else:
# 日付のフォーマットチェックしてNGなら終了
if date_formatter(dt_default_year, month, day) is None:
return
# 曜日判定処理して曜日でないなら処理終了
if not is_week_format(weekday):
return
# 処理日と入力した月日と曜日が一致した場合
if (dt_now.month, dt_now.day) == (month, day):
# 直近過去の日付を検索(ex 処理年が2024なら2023スタート)
search_day(
dt_default_year - 1, month, day, weekday, -1, is_leap_year)
# 曜日が一緒の場合
if dt_now.strftime('%A') == weekday:
# 処理日を出力
print_day(date_formatter(dt_default_year, month, day))
# 直近未来の日付を検索(ex 処理年が2024なら2025からスタート)
search_day(
dt_default_year + 1, month, day, weekday, 1, is_leap_year)
# 処理日 < 入力した月日の場合
elif (dt_now.month, dt_now.day) < (month, day):
# 直近過去の日付を検索(ex 処理年が2024なら2023スタート)
search_day(
dt_default_year - 1, month, day, weekday, -1, is_leap_year)
# 直近未来の日付を検索(ex 処理年が2024なら2024からスタート)
search_day(
dt_default_year, month, day, weekday, 1, is_leap_year)
# 処理日 > 入力した月日の場合
elif (dt_now.month, dt_now.day) > (month, day):
# 直近過去の日付を検索(ex 処理年が2024なら2024スタート)
search_day(
dt_default_year, month, day, weekday, -1, is_leap_year)
# 直近未来の日付を検索(ex 処理年が2024なら2025からスタート)
search_day(
dt_default_year + 1, month, day, weekday, 1, is_leap_year)
if __name__ == '__main__':
# ここの日付と曜日を操作する
main(2, 24, 'Monday')
・get_next_and_last_day_util.py
import calendar
from datetime import datetime
from typing import Optional
from get_next_and_last_day.const.get_next_and_last_day_const import WEEK_LIST
def is_week_format(week: str) -> bool:
"""
曜日判定処理
paramが曜日リストに含まれているか判定
:param week: 曜日
:return: True/False
"""
return week in WEEK_LIST
def date_formatter(year: int, month: int, day: int) -> Optional[datetime]:
"""
日付フォーマット処理
:param year: 年
:param month: 月
:param day: 日
:return: True: 日付型/ False: None
"""
try:
# 日付変換して返す
return datetime.strptime(
f'{str(year)}-{str(month)}-{str(day)}', '%Y-%m-%d')
except Exception as e:
# 日付に変換できなかった場合の例外処理
print(e)
return None
def print_day(target_date: datetime) -> None:
"""
結果出力処理
:param target_date: 検索結果の日付
:return: None
"""
print(target_date.strftime('%Y-%m-%d (%A)'))
def search_day(
year: int, month: int, day: int, weekday: str,
point: int, is_leap_year: bool) -> None:
"""
対象日付検索処理
:param year: 年
:param month: 月
:param day: 日
:param weekday: 曜日
:param point: 加算減算値(-1/1)
:param is_leap_year: 閏年判定フラグ(True/False)
:return: None
"""
# 閏年なら、閏年判定で取得した年で判定ループ
if is_leap_year:
year = get_leapdays(year, point)
# インプットの曜日と検索した年月日の曜日が一致するまで繰り返し
while weekday != date_formatter(year, month, day).strftime('%A'):
year = get_leapdays(year + point, point)
# 閏年以外ならインクリメント/デクリメント
else:
# インプットの曜日と検索した年月日の曜日が一致するまで繰り返し
while weekday != date_formatter(year, month, day).strftime('%A'):
year = year + point
print_day(date_formatter(year, month, day))
def get_leapdays(year: int, point: int):
"""
閏年取得処理
:param year: 年
:param point: 加算減算値(-1/1)
:return: 年(閏年)
"""
# 閏年になるまで繰り返し
while not calendar.isleap(year):
year = year + point
return year
■実行結果
▼処理日=入力日(曜日も一致)
処理日:2025年2月24日(月)
入力日:2月24日(月)
結果:
2020-02-24 (Monday)
2025-02-24 (Monday)
2031-02-24 (Monday)
▼処理日=入力日(曜日は不一致)
処理日:2025年2月24日(月)
入力日:2月24日(木)
結果:
2022-02-24 (Thursday)
2028-02-24 (Thursday)
▼処理日>入力日
処理日:2025年2月24日(月)
入力日:1月4日(木)
結果:
2024-01-04 (Thursday)
2029-01-04 (Thursday)
▼処理日<入力日
処理日:2025年2月24日(月)
入力日:9月23日(火)
結果:
2014-09-23 (Tuesday)
2025-09-23 (Tuesday)
▼処理日<入力日(閏年)
処理日:2025年2月24日(月)
入力日:2月29日(水)
結果:
2012-02-29 (Wednesday)
2040-02-29 (Wednesday)
■参考
本処理を実装するにあたり、参考とさせていただいたURLを以下に示す。
■GitHub
ソース全量はGitHub参照。
コメント