# -*- coding: utf-8 -*- import datetime from cnlunar import Lunar ZODIAC = ['鼠', '牛', '虎', '兔', '龙', '蛇', '马', '羊', '猴', '鸡', '狗', '猪'] SHICHEN = ['子时', '丑时', '寅时', '卯时', '辰时', '巳时', '午时', '未时', '申时', '酉时', '戌时', '亥时', '子时'] TIANGAN = ['甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸'] DIZHI = ['子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥'] WEEKDAYS = ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日'] def get_zodiac(year: int) -> str: """根据年份计算生肖""" return ZODIAC[(year - 4) % 12] def get_ganzhi_year(year: int) -> str: """根据年份计算干支年(如:甲辰)""" idx = (year - 4) % 60 return TIANGAN[idx % 10] + DIZHI[idx % 12] def get_ganzhi_month(year: int, month: int) -> str: """简化算法计算干支月""" idx = (year * 12 + month + 13) % 60 return TIANGAN[idx % 10] + DIZHI[idx % 12] def get_ganzhi_day(dt_date: datetime.date) -> str: """基于儒略日计算干支日""" a = (14 - dt_date.month) // 12 y = dt_date.year + 4800 - a m = dt_date.month + 12 * a - 3 jdn = dt_date.day + (153 * m + 2) // 5 + 365 * y + y // 4 - y // 100 + y // 400 - 32045 idx = (jdn + 49) % 60 return TIANGAN[idx % 10] + DIZHI[idx % 12] def _has_valid_time(dt: datetime.datetime) -> bool: """判断时间部分是否有效(非 00:00:00)""" return dt.hour != 0 or dt.minute != 0 or dt.second != 0 def get_shichen_ke(dt: datetime.datetime) -> tuple[str, int]: """根据时间计算时辰和刻数,返回 (时辰, 刻)""" lunar = Lunar(dt) shichen = SHICHEN[lunar.twohourNum] minutes_in_shichen = (dt.hour * 60 + dt.minute) % 120 ke = minutes_in_shichen // 15 + 1 return shichen, ke def format_lunar_date(dt: datetime.datetime, with_time: bool = True) -> str: """ 将公历日期格式化为农历字符串。 with_time=True 且时间有效时,追加时辰刻数。 返回示例:(乙巳年 五月初六 申时3刻) 或 (乙巳年 五月初六) """ lunar = Lunar(dt) lunar_year = f"{lunar.year8Char}年" lunar_month = lunar.lunarMonthCn.replace('大', '').replace('小', '') lunar_day = lunar.lunarDayCn if with_time and _has_valid_time(dt): shichen, ke = get_shichen_ke(dt) return f"({lunar_year} {lunar_month}{lunar_day} {shichen}{ke}刻)" return f"({lunar_year} {lunar_month}{lunar_day})"