#!/usr/bin/env python3 # coding=utf-8 # Thomas Chung # 2026-01-31 import datetime ############################################################################### # 1. Hard-coded Lunar Month Data for 2026 (KST) ############################################################################### LUNAR_MONTHS_2026 = [ # End of 2025 lunar year extending into 2026 (datetime.date(2025, 12, 20), datetime.date(2026, 1, 18), 2025, 11, False), (datetime.date(2026, 1, 19), datetime.date(2026, 2, 16), 2025, 12, False), # 2026 lunar year (Year of the Horse, no leap month) (datetime.date(2026, 2, 17), datetime.date(2026, 3, 18), 2026, 1, False), (datetime.date(2026, 3, 19), datetime.date(2026, 4, 16), 2026, 2, False), (datetime.date(2026, 4, 17), datetime.date(2026, 5, 16), 2026, 3, False), (datetime.date(2026, 5, 17), datetime.date(2026, 6, 14), 2026, 4, False), (datetime.date(2026, 6, 15), datetime.date(2026, 7, 13), 2026, 5, False), (datetime.date(2026, 7, 14), datetime.date(2026, 8, 12), 2026, 6, False), (datetime.date(2026, 8, 13), datetime.date(2026, 9, 10), 2026, 7, False), (datetime.date(2026, 9, 11), datetime.date(2026, 10, 9), 2026, 8, False), (datetime.date(2026, 10, 10), datetime.date(2026, 11, 8), 2026, 9, False), (datetime.date(2026, 11, 9), datetime.date(2026, 12, 8), 2026, 10, False), (datetime.date(2026, 12, 9), datetime.date(2027, 1, 7), 2026, 11, False), (datetime.date(2027, 1, 8), datetime.date(2027, 2, 5), 2026, 12, False), ] ############################################################################### # 2. Important Dates (in Korean) for 2026 ############################################################################### IMPORTANT_DATES_2026 = { # Solar-based holidays datetime.date(2026, 1, 1): "신정", datetime.date(2026, 2, 16): "설날 전날", datetime.date(2026, 2, 17): "설날", datetime.date(2026, 2, 18): "설날 다음 날", datetime.date(2026, 3, 1): "삼일절", datetime.date(2026, 3, 2): "대체공휴일", datetime.date(2026, 5, 5): "어린이날", datetime.date(2026, 5, 24): "부처님 오신 날", datetime.date(2026, 5, 25): "대체공휴일", datetime.date(2026, 6, 6): "현충일", datetime.date(2026, 7, 17): "제헌절", datetime.date(2026, 8, 15): "광복절", datetime.date(2026, 8, 17): "대체공휴일", datetime.date(2026, 9, 24): "추석 전날", datetime.date(2026, 9, 25): "추석", datetime.date(2026, 9, 26): "추석 다음 날", datetime.date(2026, 10, 3): "개천절", datetime.date(2026, 10, 5): "대체공휴일", datetime.date(2026, 10, 9): "한글날", datetime.date(2026, 12, 25): "성탄절", } ############################################################################### # 3. Functions to Build and Render the Calendar ############################################################################### def get_korean_lunar_date(gregorian_date): """ Returns (lunar_year, lunar_month, lunar_day, is_leap) if within 2026 data, else None. """ for (start_date, end_date, lunar_year, lunar_month, is_leap) in LUNAR_MONTHS_2026: if start_date <= gregorian_date <= end_date: day_in_lunar_month = (gregorian_date - start_date).days + 1 return (lunar_year, lunar_month, day_in_lunar_month, is_leap) return None def build_month_calendar_matrix(year, month): """ Returns a list-of-lists (6 rows x 7 cols) for a Sunday-start layout. Each cell = (date_obj, lunar_info) or None. """ first_day = datetime.date(year, month, 1) # Python weekday(): Monday=0, Sunday=6 => offset = (weekday+1) % 7 offset = (first_day.weekday() + 1) % 7 if month == 12: next_month = datetime.date(year + 1, 1, 1) else: next_month = datetime.date(year, month + 1, 1) last_day = next_month - datetime.timedelta(days=1) rows = [[None]*7 for _ in range(6)] current_day = 1 row = 0 col = offset while current_day <= last_day.day: current_date = datetime.date(year, month, current_day) lunar_info = get_korean_lunar_date(current_date) rows[row][col] = (current_date, lunar_info) current_day += 1 col += 1 if col > 6: col = 0 row += 1 if row > 5: break return rows def generate_month_table_html(year, month): """ Generates an HTML snippet for one month's calendar table, including lunar dates and holiday highlights for 2026. """ day_of_week_labels = ["일", "월", "화", "수", "목", "금", "토"] calendar_matrix = build_month_calendar_matrix(year, month) month_kor = f"{month}월" lines = [] # Centered heading lines.append( f"
| {label} | ") lines.append("|
|---|---|
| ") else: (date_obj, lunar_info) = cell solar_day = date_obj.day # Check if there's a holiday holiday_name = IMPORTANT_DATES_2026.get(date_obj, None) # Check lunar info if lunar_info is not None: (lyear, lmonth, lday, is_leap) = lunar_info lunar_str = f"윤{lmonth}/{lday}" if is_leap else f"{lmonth}/{lday}" else: lunar_str = "N/A" # Base text: Solar day + (Lunar day) cell_html = f"{solar_day} | {cell_html} | ") lines.append("