# converter.py import os import json from datetime import datetime from typing import List, Optional class Converter: """ 提供西曆與農曆互轉功能,並能判斷特定年份的閏月。 """ LUNAR_JSON_DIR = 'lunar_json' def __init__(self): """初始化時,建立一個空的快取來存放已查詢過的年份閏月資訊。""" self._leap_month_cache = {} @classmethod def load_solar_to_lunar(cls, year: int) -> dict: """這是一個類別方法,用來載入指定年份的資料檔。""" path = os.path.join(cls.LUNAR_JSON_DIR, f"{year}.json") if not os.path.exists(path): raise FileNotFoundError(f"找不到農曆資料檔: {path}") with open(path, encoding='utf-8') as f: return json.load(f) def solar_to_lunar(self, solar_date_str: str) -> dict: try: dt = datetime.strptime(solar_date_str, '%Y-%m-%d').date() except ValueError: raise ValueError("西曆日期格式應為 YYYY-MM-DD") # 【修正點】從 self. 呼叫改為 Converter. 呼叫 data = Converter.load_solar_to_lunar(dt.year) if solar_date_str not in data: raise KeyError(f"沒有找到對應 {solar_date_str} 的農曆資料") return data[solar_date_str] def lunar_to_solar(self, lunar_year: int, lunar_month: int, lunar_day: int, leap: bool=False) -> str: years_to_check = {lunar_year, lunar_year + 1} for year in sorted(list(years_to_check)): try: # 【修正點】從 self. 呼叫改為 Converter. 呼叫 data = Converter.load_solar_to_lunar(year) for solar_date, info in data.items(): lstr = info.get('農曆', '') is_leap = lstr.startswith('閏') core = lstr[1:] if is_leap else lstr if not all(c in core for c in ['月', '日']): continue m_str, d_str = core.replace('月','-').replace('日','').split('-') if int(m_str) == lunar_month and int(d_str) == lunar_day and is_leap == leap: return info.get("西曆") except FileNotFoundError: continue raise KeyError(f"找不到對應農曆 {lunar_year}{'閏' if leap else ''}{lunar_month}月{lunar_day}日 的西曆") def lunar_to_solar_all(self, lunar_year: int, lunar_month: int, lunar_day: int) -> List[str]: results = [] try: solar_date = self.lunar_to_solar(lunar_year, lunar_month, lunar_day, leap=False) results.append(solar_date) except KeyError: pass try: solar_date = self.lunar_to_solar(lunar_year, lunar_month, lunar_day, leap=True) results.append(solar_date) except KeyError: pass return results def get_leap_month(self, year: int) -> Optional[int]: if year in self._leap_month_cache: return self._leap_month_cache[year] try: # 【修正點】從 self. 呼叫改為 Converter. 呼叫 data = Converter.load_solar_to_lunar(year) for info in data.values(): lstr = info.get('農曆', '') if lstr.startswith('閏'): core = lstr[1:] if '月' in core: month_str = core.split('月')[0] leap_month = int(month_str) self._leap_month_cache[year] = leap_month return leap_month self._leap_month_cache[year] = None return None except FileNotFoundError: self._leap_month_cache[year] = None return None # ... (main 函式不變) ... def main(): """展示 Converter 的新功能:查詢閏月""" print("=== Converter 閏月判斷功能展示 ===") try: converter = Converter() years_to_test = [1976, 1977, 2023, 2024, 2025] for year in years_to_test: leap_month = converter.get_leap_month(year) if leap_month: print(f"西曆 {year} 年,有閏月,是閏 {leap_month} 月。") else: print(f"西曆 {year} 年,沒有閏月。") except Exception as e: print(f"\n發生錯誤: {e}") if __name__ == '__main__': main()