#!/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"

" f"{year}년 {month_kor}

" ) lines.append("") lines.append(" ") for label in day_of_week_labels: lines.append(f" ") lines.append(" ") lines.append(" ") for row in calendar_matrix: lines.append(" ") for cell in row: if cell is None: 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}
({lunar_str})" # If there's a holiday, display it in red if holiday_name: cell_html += f"
{holiday_name}" lines.append(f"") lines.append(" ") lines.append(" ") lines.append("
{label}
{cell_html}
") return "\n".join(lines) def lunar_2026(): """ Builds one big HTML document for Jan~Dec 2026, with lunar data & holidays. """ html_parts = [] html_parts.append("") html_parts.append("") html_parts.append("") html_parts.append(" ") html_parts.append(" 2026년 한국달력") # Basic CSS html_parts.append(" ") html_parts.append("") html_parts.append("") html_parts.append("

2026년 한국달력 (음력 포함)

") # Generate each month for m in range(1, 13): month_html = generate_month_table_html(2026, m) html_parts.append(f"
{month_html}
") html_parts.append("") html_parts.append("") return "\n".join(html_parts) def main(): html_content = lunar_2026() filename = "2026.html" with open(filename, "w", encoding="utf-8") as f: f.write(html_content) print(f"달력이 '{filename}' 파일로 생성되었습니다.") if __name__ == "__main__": main()