Files
lunar-converter/converter.py
Timmy ae21a0ae66 Initial commit: Lunar calendar converter project
- Add lunar calendar astronomical calculation engine (lunar_calendar.py)
- Add converter utilities for solar/lunar date conversion
- Add historical era name conversions (chrono_converter.py, converter_with_eras.py)
- Add FastAPI REST API for date conversion services
- Add age calculator using lunar calendar
- Add batch generation script for lunar calendar JSON data
- Add project documentation (CLAUDE.md, pyproject.toml)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-09 13:51:45 +08:00

108 lines
4.3 KiB
Python

# 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()