from datetime import datetime try: from lunar_python import Lunar, Solar except ImportError: # pragma: no cover - production image installs the package Lunar = None Solar = None class BaziCalculator: def calculate(self, payload: dict) -> dict: birth_date = payload["birth_date"] time_unknown = bool(payload.get("time_unknown")) birth_time = payload.get("birth_time") if not time_unknown else "12:00" hour, minute = self._parse_time(birth_time or "12:00") year, month, day = self._parse_date(birth_date) calendar_type = payload.get("calendar_type", "solar") if Solar and Lunar: if calendar_type == "lunar": lunar_month = -month if payload.get("is_leap_month") else month lunar = Lunar.fromYmdHms(year, lunar_month, day, hour, minute, 0) solar = lunar.getSolar() else: solar = Solar.fromYmdHms(year, month, day, hour, minute, 0) lunar = solar.getLunar() eight = lunar.getEightChar() return { "calendar_type": calendar_type, "is_leap_month": bool(payload.get("is_leap_month")), "birth_date": birth_date, "birth_time": None if time_unknown else f"{hour:02d}:{minute:02d}", "time_unknown": time_unknown, "birth_place": payload.get("birth_place"), "nickname": payload.get("nickname"), "gender": payload.get("gender"), "solar_date": f"{solar.getYear():04d}-{solar.getMonth():02d}-{solar.getDay():02d}", "lunar_date": f"{lunar.getYear()}年{lunar.getMonth()}月{lunar.getDay()}日", "pillars": { "year": eight.getYear(), "month": eight.getMonth(), "day": eight.getDay(), "time": eight.getTime() if not time_unknown else "时辰不详", }, "wuxing": { "year": eight.getYearWuXing(), "month": eight.getMonthWuXing(), "day": eight.getDayWuXing(), "time": eight.getTimeWuXing() if not time_unknown else "时辰不详", }, "shi_shen": { "year": eight.getYearShiShenGan(), "month": eight.getMonthShiShenGan(), "day": "日主", "time": eight.getTimeShiShenGan() if not time_unknown else "时辰不详", }, "day_master": eight.getDayGan(), } return self._fallback_chart(payload, year, month, day, hour, minute, time_unknown) def _fallback_chart(self, payload: dict, year: int, month: int, day: int, hour: int, minute: int, time_unknown: bool) -> dict: stems = "甲乙丙丁戊己庚辛壬癸" branches = "子丑寅卯辰巳午未申酉戌亥" seed = year * 372 + month * 31 + day + hour def pillar(offset: int) -> str: return stems[(seed + offset) % 10] + branches[(seed + offset) % 12] return { "calendar_type": payload.get("calendar_type", "solar"), "is_leap_month": bool(payload.get("is_leap_month")), "birth_date": payload["birth_date"], "birth_time": None if time_unknown else f"{hour:02d}:{minute:02d}", "time_unknown": time_unknown, "birth_place": payload.get("birth_place"), "nickname": payload.get("nickname"), "gender": payload.get("gender"), "solar_date": payload["birth_date"], "lunar_date": "本地未安装 lunar_python,暂用娱乐排盘", "pillars": { "year": pillar(0), "month": pillar(13), "day": pillar(27), "time": pillar(41) if not time_unknown else "时辰不详", }, "wuxing": {"year": "参考", "month": "参考", "day": "参考", "time": "参考"}, "shi_shen": {"year": "参考", "month": "参考", "day": "日主", "time": "参考"}, "day_master": pillar(27)[0], } def _parse_date(self, value: str) -> tuple[int, int, int]: parsed = datetime.strptime(value, "%Y-%m-%d") return parsed.year, parsed.month, parsed.day def _parse_time(self, value: str) -> tuple[int, int]: parsed = datetime.strptime(value, "%H:%M") return parsed.hour, parsed.minute