Python第何何曜日(第2月曜日など)の日付を取得する方法【完全解説】
Pythonで「第2月曜日」「第3金曜日」などの第N曜日の日付を取得する方法を詳しく解説します。基本的な実装から祝日対応まで、実用的なサンプルコードとともに学びましょう。
基本的な第N曜日の取得
基本実装
from datetime import date, timedelta
import calendar
def get_nth_weekday(year, month, weekday, n):
"""指定月の第N曜日を取得
Args:
year: 年
month: 月
weekday: 曜日 (0=月曜日, 1=火曜日, ..., 6=日曜日)
n: 第何曜日か (1, 2, 3, 4, 5)
Returns:
date: 該当日付、存在しない場合はNone
"""
# 月の1日を取得
first_day = date(year, month, 1)
# 1日から指定曜日までの日数を計算
days_until_target = (weekday - first_day.weekday()) % 7
# 第1指定曜日の日付
first_target = first_day + timedelta(days=days_until_target)
# 第N指定曜日の日付
target_date = first_target + timedelta(weeks=n-1)
# 同じ月内かチェック
if target_date.month == month and target_date.year == year:
return target_date
else:
return None
# 使用例
year = 2024
month = 1
# 各種第N曜日を取得
weekday_names = ['月', '火', '水', '木', '金', '土', '日']
print(f"=== {year}年{month}月の第N曜日 ===")
for weekday_index, weekday_name in enumerate(weekday_names):
print(f"\n{weekday_name}曜日:")
for n in range(1, 6):
nth_date = get_nth_weekday(year, month, weekday_index, n)
if nth_date:
print(f" 第{n}{weekday_name}曜日: {nth_date}")
else:
print(f" 第{n}{weekday_name}曜日: なし")
より詳細な情報を含む実装
def get_nth_weekday_detailed(year, month, weekday, n):
"""第N曜日の詳細情報を取得"""
target_date = get_nth_weekday(year, month, weekday, n)
if target_date is None:
return None
# 月内での順序を計算
month_calendar = calendar.monthcalendar(year, month)
week_number = None
day_in_week = None
for week_idx, week in enumerate(month_calendar):
if target_date.day in week:
week_number = week_idx + 1
day_in_week = week.index(target_date.day)
break
weekday_names = ['月', '火', '水', '木', '金', '土', '日']
return {
'date': target_date,
'weekday_name': weekday_names[weekday],
'nth': n,
'week_of_month': week_number,
'day_of_month': target_date.day,
'is_month_end': target_date.day > 25 # 月末に近いかの目安
}
# 使用例
detailed_info = get_nth_weekday_detailed(2024, 1, 0, 2) # 第2月曜日
if detailed_info:
print(f"第{detailed_info['nth']}{detailed_info['weekday_name']}曜日: {detailed_info['date']}")
print(f"月の第{detailed_info['week_of_month']}週目")
print(f"月の{detailed_info['day_of_month']}日目")
複数月・複数年の第N曜日取得
年間の第N曜日一覧
def get_yearly_nth_weekdays(year, weekday, n):
"""年間の第N曜日を一覧取得"""
yearly_dates = []
weekday_names = ['月', '火', '水', '木', '金', '土', '日']
for month in range(1, 13):
nth_date = get_nth_weekday(year, month, weekday, n)
month_info = {
'year': year,
'month': month,
'date': nth_date,
'exists': nth_date is not None
}
if nth_date:
month_info.update({
'day': nth_date.day,
'weekday_name': weekday_names[weekday],
'nth': n
})
yearly_dates.append(month_info)
return yearly_dates
# 使用例:2024年の第2金曜日
second_fridays = get_yearly_nth_weekdays(2024, 4, 2) # 4=金曜日
print("=== 2024年 各月の第2金曜日 ===")
for month_data in second_fridays:
if month_data['exists']:
print(f"{month_data['month']:2d}月: {month_data['date']} ({month_data['day']:2d}日)")
else:
print(f"{month_data['month']:2d}月: なし")
複数年間の比較
def compare_nth_weekdays_across_years(years, weekday, n):
"""複数年間の第N曜日を比較"""
comparison_data = []
for year in years:
year_data = get_yearly_nth_weekdays(year, weekday, n)
comparison_data.append({
'year': year,
'months': year_data,
'total_occurrences': sum(1 for m in year_data if m['exists']),
'missing_months': [m['month'] for m in year_data if not m['exists']]
})
return comparison_data
# 使用例:複数年の第5金曜日比較
years = [2023, 2024, 2025]
fifth_fridays_comparison = compare_nth_weekdays_across_years(years, 4, 5)
print("=== 複数年の第5金曜日比較 ===")
for year_data in fifth_fridays_comparison:
print(f"{year_data['year']}年: {year_data['total_occurrences']}回発生")
if year_data['missing_months']:
print(f" 発生しない月: {year_data['missing_months']}")
特定パターンの第N曜日
月の最初と最後の指定曜日
def get_first_and_last_weekday(year, month, weekday):
"""月の最初と最後の指定曜日を取得"""
first_weekday = get_nth_weekday(year, month, weekday, 1)
# 最後の指定曜日を取得
last_weekday = None
for n in range(5, 0, -1): # 5から1まで逆順で検索
candidate = get_nth_weekday(year, month, weekday, n)
if candidate:
last_weekday = candidate
break
return {
'first': first_weekday,
'last': last_weekday,
'count': len([get_nth_weekday(year, month, weekday, n)
for n in range(1, 6)
if get_nth_weekday(year, month, weekday, n) is not None])
}
# 使用例
year = 2024
month = 1
weekday = 0 # 月曜日
first_last = get_first_and_last_weekday(year, month, weekday)
print(f"{year}年{month}月の月曜日:")
print(f"最初: {first_last['first']}")
print(f"最後: {first_last['last']}")
print(f"総数: {first_last['count']}回")
偶数・奇数週の曜日
def get_even_odd_weekdays(year, month, weekday, parity='even'):
"""偶数週または奇数週の指定曜日を取得
Args:
parity: 'even' (偶数週) または 'odd' (奇数週)
"""
weekdays = []
for n in range(1, 6):
nth_date = get_nth_weekday(year, month, weekday, n)
if nth_date:
if parity == 'even' and n % 2 == 0:
weekdays.append({'date': nth_date, 'nth': n})
elif parity == 'odd' and n % 2 == 1:
weekdays.append({'date': nth_date, 'nth': n})
return weekdays
# 使用例
even_mondays = get_even_odd_weekdays(2024, 1, 0, 'even')
odd_mondays = get_even_odd_weekdays(2024, 1, 0, 'odd')
print("2024年1月の月曜日:")
print("偶数週:", [d['date'] for d in even_mondays])
print("奇数週:", [d['date'] for d in odd_mondays])
祝日・営業日を考慮した第N曜日
営業日としての第N曜日
def get_nth_business_weekday(year, month, n, holidays=None):
"""第N営業日を取得(土日祝除く)"""
if holidays is None:
holidays = set()
else:
holidays = set(holidays)
current_date = date(year, month, 1)
_, last_day = calendar.monthrange(year, month)
month_end = date(year, month, last_day)
business_day_count = 0
while current_date <= month_end:
# 平日かつ祝日でない場合
if current_date.weekday() < 5 and current_date not in holidays:
business_day_count += 1
if business_day_count == n:
return current_date
current_date += timedelta(days=1)
return None
# 使用例
# 簡略化した祝日リスト
holidays_2024 = [
date(2024, 1, 1), # 元日
date(2024, 2, 11), # 建国記念の日
date(2024, 4, 29), # 昭和の日
]
print("2024年1月の営業日:")
for n in range(1, 11):
business_day = get_nth_business_weekday(2024, 1, n, holidays_2024)
if business_day:
weekday_name = ['月', '火', '水', '木', '金', '土', '日'][business_day.weekday()]
print(f"第{n:2d}営業日: {business_day} ({weekday_name})")
祝日の振替を考慮した第N曜日
def get_nth_weekday_with_holiday_shift(year, month, weekday, n, holidays=None):
"""祝日の場合は次の営業日に振替える第N曜日"""
target_date = get_nth_weekday(year, month, weekday, n)
if target_date is None:
return None
if holidays is None:
holidays = set()
else:
holidays = set(holidays)
# 祝日または週末の場合は次の営業日を探す
while (target_date.weekday() >= 5 or # 週末
target_date in holidays): # 祝日
target_date += timedelta(days=1)
# 月を超えた場合は処理を停止
if target_date.month != month:
return None
return target_date
# 使用例
original_date = get_nth_weekday(2024, 2, 0, 2) # 第2月曜日
shifted_date = get_nth_weekday_with_holiday_shift(2024, 2, 0, 2, holidays_2024)
print(f"2024年2月第2月曜日:")
print(f"元の日付: {original_date}")
print(f"振替後: {shifted_date}")
実用的な応用例
定期会議のスケジュール生成
class MeetingScheduler:
def __init__(self, holidays=None):
self.holidays = set(holidays) if holidays else set()
self.weekday_names = ['月', '火', '水', '木', '金', '土', '日']
def schedule_regular_meeting(self, year, weekday, nth, months=None):
"""定期会議のスケジュールを生成"""
if months is None:
months = range(1, 13)
schedule = []
for month in months:
meeting_date = get_nth_weekday(year, month, weekday, nth)
if meeting_date:
# 祝日チェック
is_holiday = meeting_date in self.holidays
# 振替日の計算
if is_holiday or meeting_date.weekday() >= 5:
alternative_date = self._find_alternative_date(meeting_date, month)
else:
alternative_date = meeting_date
meeting_info = {
'month': month,
'scheduled_date': meeting_date,
'actual_date': alternative_date,
'weekday_name': self.weekday_names[weekday],
'nth': nth,
'is_holiday': is_holiday,
'needs_shift': meeting_date != alternative_date
}
schedule.append(meeting_info)
return schedule
def _find_alternative_date(self, original_date, month):
"""代替日を探す"""
alternative = original_date
while (alternative.weekday() >= 5 or
alternative in self.holidays):
alternative += timedelta(days=1)
# 月を超えた場合は前の営業日を探す
if alternative.month != month:
alternative = original_date - timedelta(days=1)
while (alternative.weekday() >= 5 or
alternative in self.holidays):
alternative -= timedelta(days=1)
break
return alternative
# 使用例
scheduler = MeetingScheduler(holidays_2024)
meeting_schedule = scheduler.schedule_regular_meeting(2024, 1, 2) # 第2火曜日
print("=== 2024年 月例会議スケジュール(第2火曜日)===")
for meeting in meeting_schedule:
if meeting['needs_shift']:
print(f"{meeting['month']:2d}月: {meeting['scheduled_date']} → {meeting['actual_date']} (振替)")
else:
print(f"{meeting['month']:2d}月: {meeting['actual_date']}")
給与支給日の計算
def calculate_salary_dates(year, pay_weekday=4, pay_nth=4):
"""給与支給日を計算(例:第4金曜日)"""
salary_schedule = []
for month in range(1, 13):
pay_date = get_nth_weekday(year, month, pay_weekday, pay_nth)
# 第4金曜日が存在しない場合は最終金曜日
if pay_date is None:
for n in range(5, 0, -1):
pay_date = get_nth_weekday(year, month, pay_weekday, n)
if pay_date:
break
salary_info = {
'month': month,
'pay_date': pay_date,
'is_standard': pay_date == get_nth_weekday(year, month, pay_weekday, pay_nth),
'weekday': ['月', '火', '水', '木', '金', '土', '日'][pay_date.weekday()] if pay_date else None
}
salary_schedule.append(salary_info)
return salary_schedule
# 使用例
salary_dates = calculate_salary_dates(2024, 4, 4) # 第4金曜日
print("=== 2024年 給与支給予定日(第4金曜日基準)===")
for salary in salary_dates:
standard_note = "" if salary['is_standard'] else " (最終金曜日)"
print(f"{salary['month']:2d}月: {salary['pay_date']} ({salary['weekday']}){standard_note}")
イベントスケジューラー
class EventScheduler:
def __init__(self):
self.weekday_names = ['月', '火', '水', '木', '金', '土', '日']
def create_event_series(self, year, events_config):
"""複数のイベントシリーズを作成
events_config: [
{'name': 'イベント名', 'weekday': 曜日, 'nth': 第何週, 'months': [月リスト]},
...
]
"""
all_events = []
for config in events_config:
name = config['name']
weekday = config['weekday']
nth = config['nth']
months = config.get('months', range(1, 13))
for month in months:
event_date = get_nth_weekday(year, month, weekday, nth)
if event_date:
event_info = {
'name': name,
'date': event_date,
'month': month,
'weekday_name': self.weekday_names[weekday],
'nth': nth,
'config': config
}
all_events.append(event_info)
# 日付順にソート
all_events.sort(key=lambda x: x['date'])
return all_events
def find_conflicts(self, events):
"""イベントの日程重複をチェック"""
conflicts = []
for i, event1 in enumerate(events):
for event2 in events[i+1:]:
if event1['date'] == event2['date']:
conflicts.append({
'date': event1['date'],
'events': [event1['name'], event2['name']]
})
return conflicts
# 使用例
events_config = [
{
'name': '月例会議',
'weekday': 1, # 火曜日
'nth': 2, # 第2週
'months': range(1, 13)
},
{
'name': '四半期レビュー',
'weekday': 4, # 金曜日
'nth': 2, # 第2週
'months': [3, 6, 9, 12]
},
{
'name': 'チームビルディング',
'weekday': 4, # 金曜日
'nth': 1, # 第1週
'months': [2, 5, 8, 11]
}
]
scheduler = EventScheduler()
events = scheduler.create_event_series(2024, events_config)
conflicts = scheduler.find_conflicts(events)
print("=== 2024年 イベントスケジュール ===")
current_month = 0
for event in events:
if event['month'] != current_month:
print(f"\n{event['month']}月:")
current_month = event['month']
print(f" {event['date']} ({event['weekday_name']}): {event['name']}")
if conflicts:
print("\n=== 日程重複 ===")
for conflict in conflicts:
print(f"{conflict['date']}: {' vs '.join(conflict['events'])}")
学校行事カレンダー
def create_school_calendar(year, start_month=4):
"""学校行事カレンダーを作成(4月始まり)"""
school_events = []
# 学期の定義
semesters = {
1: list(range(4, 8)), # 1学期: 4-7月
2: list(range(9, 13)), # 2学期: 9-12月
3: [1, 2, 3] # 3学期: 1-3月
}
# 各学期の行事
semester_events = {
1: [
{'name': '始業式', 'weekday': 0, 'nth': 1, 'month': 4}, # 4月第1月曜日
{'name': '運動会', 'weekday': 5, 'nth': 2, 'month': 5}, # 5月第2土曜日
{'name': '終業式', 'weekday': 4, 'nth': 3, 'month': 7}, # 7月第3金曜日
],
2: [
{'name': '始業式', 'weekday': 0, 'nth': 1, 'month': 9}, # 9月第1月曜日
{'name': '文化祭', 'weekday': 6, 'nth': 2, 'month': 10}, # 10月第2日曜日
{'name': '終業式', 'weekday': 4, 'nth': 3, 'month': 12}, # 12月第3金曜日
],
3: [
{'name': '始業式', 'weekday': 1, 'nth': 2, 'month': 1}, # 1月第2火曜日
{'name': '卒業式', 'weekday': 4, 'nth': 3, 'month': 3}, # 3月第3金曜日
]
}
for semester, events in semester_events.items():
for event_config in events:
event_date = get_nth_weekday(
year,
event_config['month'],
event_config['weekday'],
event_config['nth']
)
if event_date:
school_events.append({
'name': event_config['name'],
'date': event_date,
'semester': semester,
'month': event_config['month']
})
# 日付順にソート
school_events.sort(key=lambda x: x['date'])
return school_events
# 使用例
school_calendar = create_school_calendar(2024)
print("=== 2024年度 学校行事カレンダー ===")
current_semester = 0
for event in school_calendar:
if event['semester'] != current_semester:
semester_name = ['', '1学期', '2学期', '3学期'][event['semester']]
print(f"\n{semester_name}:")
current_semester = event['semester']
weekday_name = ['月', '火', '水', '木', '金', '土', '日'][event['date'].weekday()]
print(f" {event['date']} ({weekday_name}): {event['name']}")
統計分析機能
def analyze_nth_weekday_patterns(year, weekday, max_nth=5):
"""第N曜日の出現パターンを分析"""
analysis = {
'year': year,
'weekday': weekday,
'weekday_name': ['月', '火', '水', '木', '金', '土', '日'][weekday],
'monthly_counts': {},
'nth_occurrences': {n: 0 for n in range(1, max_nth + 1)},
'total_occurrences': 0
}
for month in range(1, 13):
month_count = 0
for nth in range(1, max_nth + 1):
nth_date = get_nth_weekday(year, month, weekday, nth)
if nth_date:
month_count += 1
analysis['nth_occurrences'][nth] += 1
analysis['total_occurrences'] += 1
analysis['monthly_counts'][month] = month_count
# 統計計算
monthly_counts = list(analysis['monthly_counts'].values())
analysis['statistics'] = {
'avg_per_month': sum(monthly_counts) / 12,
'min_per_month': min(monthly_counts),
'max_per_month': max(monthly_counts),
'months_with_5': sum(1 for count in monthly_counts if count == 5)
}
return analysis
# 使用例
friday_analysis = analyze_nth_weekday_patterns(2024, 4) # 金曜日
print(f"=== 2024年 {friday_analysis['weekday_name']}曜日 出現パターン分析 ===")
print(f"年間総出現回数: {friday_analysis['total_occurrences']}回")
print(f"月平均: {friday_analysis['statistics']['avg_per_month']:.1f}回")
print(f"最少月: {friday_analysis['statistics']['min_per_month']}回")
print(f"最多月: {friday_analysis['statistics']['max_per_month']}回")
print(f"5回ある月: {friday_analysis['statistics']['months_with_5']}月")
print("\n第N金曜日の年間出現回数:")
for nth, count in friday_analysis['nth_occurrences'].items():
print(f" 第{nth}金曜日: {count}回")
カスタム検索機能
def find_specific_date_patterns(year, criteria):
"""特定の条件に合う日付パターンを検索
criteria例:
{
'weekdays': [0, 4], # 月曜日と金曜日
'nth_values': [1, 3], # 第1と第3
'months': [1, 2, 3], # 1-3月
'min_gap_days': 5 # 最小間隔5日
}
"""
matching_dates = []
weekdays = criteria.get('weekdays', range(7))
nth_values = criteria.get('nth_values', range(1, 6))
months = criteria.get('months', range(1, 13))
min_gap_days = criteria.get('min_gap_days', 0)
for month in months:
for weekday in weekdays:
for nth in nth_values:
target_date = get_nth_weekday(year, month, weekday, nth)
if target_date:
# 最小間隔チェック
if min_gap_days > 0 and matching_dates:
last_date = matching_dates[-1]['date']
gap = (target_date - last_date).days
if gap < min_gap_days:
continue
weekday_name = ['月', '火', '水', '木', '金', '土', '日'][weekday]
matching_dates.append({
'date': target_date,
'month': month,
'weekday': weekday,
'weekday_name': weekday_name,
'nth': nth
})
return matching_dates
# 使用例
search_criteria = {
'weekdays': [0, 4], # 月曜日と金曜日
'nth_values': [1, 3], # 第1と第3
'months': [1, 2, 3, 4, 5, 6], # 上半期
'min_gap_days': 7 # 最低1週間の間隔
}
search_results = find_specific_date_patterns(2024, search_criteria)
print("=== カスタム検索結果 ===")
print("条件: 上半期の第1・第3月曜日・金曜日(最低1週間間隔)")
for result in search_results:
print(f"{result['date']} ({result['weekday_name']}) - 第{result['nth']}{result['weekday_name']}曜日")
まとめ
- 基本機能:月の1日から計算して第N曜日を特定
- 存在チェック:月をまたがないかの検証が重要
- 祝日対応:振替日の自動計算機能
- 実用例:会議スケジュール、給与日、学校行事
- 分析機能:出現パターンの統計分析
- 検索機能:複雑な条件での日付パターン検索
これらの実装により、様々なビジネスシーンでの定期的な日程管理が効率的に行えます。
■プロンプトだけでオリジナルアプリを開発・公開してみた!!
■AI時代の第一歩!「AI駆動開発コース」はじめました!
テックジム東京本校で先行開始。
■テックジム東京本校
「武田塾」のプログラミング版といえば「テックジム」。
講義動画なし、教科書なし。「進捗管理とコーチング」で効率学習。
より早く、より安く、しかも対面型のプログラミングスクールです。
<短期講習>5日で5万円の「Pythonミニキャンプ」開催中。
<月1開催>放送作家による映像ディレクター養成講座
<オンライン無料>ゼロから始めるPython爆速講座


