70 lines
2.5 KiB
Python
70 lines
2.5 KiB
Python
# -*- 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})"
|