Files
lunar-converter/age_calculator.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

100 lines
3.9 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# age_calculator.py
import datetime
from collections import namedtuple
from loguru import logger # type: ignore[reportMissingImports]
# 從 converter.py 這個檔案,匯入 Converter 這個 class
from converter import Converter
# --- 類型定義 ---
AgeResult = namedtuple("AgeResult", ["real_age", "east_asian_age"])
# ======================================================================
# 主要類別AgeCalculator
# ======================================================================
class AgeCalculator:
"""
提供精準的年齡計算功能 (實歲與虛歲)。
初始化時需要傳入一個 Converter 物件。
"""
def __init__(self, converter: Converter):
"""
初始化年齡計算機。
這個設計模式稱為「依賴注入 (Dependency Injection)」,
AgeCalculator 本身不建立 Converter而是由外部提供讓架構更靈活。
:param converter: 一個 Converter 的實體物件。
"""
if not isinstance(converter, Converter):
raise TypeError("初始化 AgeCalculator 時,必須提供一個有效的 Converter 物件")
self.converter = converter
def calculate(
self,
solar_birth_date: datetime.date,
lunar_birth_info: dict,
today: datetime.date
) -> AgeResult:
"""
根據生日資訊,使用農曆轉換器精準計算實歲和虛歲。
"""
# 虛歲計算 (邏輯不變)
east_asian_age = today.year - solar_birth_date.year + 1
# 實歲計算 (使用 self.converter)
try:
# 用 converter 找出「今年的農曆生日」對應的西曆日期
this_year_lunar_bday_solar_str = self.converter.lunar_to_solar(
lunar_year=today.year,
lunar_month=lunar_birth_info['month'],
lunar_day=lunar_birth_info['day'],
leap=lunar_birth_info['leap']
)
this_year_lunar_bday_date = datetime.datetime.strptime(this_year_lunar_bday_solar_str, '%Y-%m-%d').date()
except KeyError:
# Edge case: 若今年沒有該農曆日期(如閏月),則認定生日已過,讓邏輯更強健
this_year_lunar_bday_date = today - datetime.timedelta(days=1)
real_age = today.year - solar_birth_date.year
# 核心判斷:如果今天還沒到「今年的農曆生日(的西曆日期)」,那實歲就 -1
if today < this_year_lunar_bday_date:
real_age -= 1
return AgeResult(real_age=real_age, east_asian_age=east_asian_age)
# ======================================================================
# 主程式區塊:作為使用範例
# ======================================================================
if __name__ == "__main__":
# --- 作為範例的資料 ---
TODAY_OVERRIDE = datetime.date(2025, 7, 30)
SOLAR_BIRTH_DATE_STR = "1977-10-12"
LUNAR_BIRTH_INFO = {"month": 8, "day": 30, "leap": False}
try:
# --- 步驟 1: 建立依賴物件 (工具人) ---
converter = Converter()
# --- 步驟 2: 建立主物件,並注入依賴 (主角登場,並把工具人交給他) ---
age_calculator = AgeCalculator(converter=converter)
# --- 步驟 3: 執行計算 (叫主角開始幹活) ---
solar_birth_date = datetime.datetime.strptime(SOLAR_BIRTH_DATE_STR, "%Y-%m-%d").date()
age_result = age_calculator.calculate(
solar_birth_date=solar_birth_date,
lunar_birth_info=LUNAR_BIRTH_INFO,
today=TODAY_OVERRIDE,
)
# --- 步驟 4: 使用 loguru 輸出結果 ---
logger.remove()
logger.add(lambda msg: print(msg, end=""), format="{message}")
logger.info(f"實歲 (足歲){age_result.real_age} 歲。")
logger.info(f"虛歲:{age_result.east_asian_age} 歲。")
except Exception as e:
logger.error(f"執行時發生錯誤: {e}")