Source code for src.core.checker

"""
生日检查模块
"""
from datetime import datetime, timedelta, date
from typing import List, Tuple, Dict, Union
from lunar_python import Solar
from src.core.config import Recipient
import logging

logger = logging.getLogger(__name__)


[docs] class BirthdayChecker:
[docs] def check_birthdays(self, recipients: List[Recipient]) -> List[Tuple[Recipient, bool, Dict]]: """ 检查所有人的生日 Args: recipients: 收件人列表 Returns: List[Tuple[Recipient, bool, Dict]]: 返回收件人、是否生日和额外信息的元组列表 """ today = datetime.now() results = [] for recipient in recipients: is_birthday, extra_info = self._check_birthday(recipient, today) results.append((recipient, is_birthday, extra_info)) return results
def _convert_to_date_parts(self, date_obj: Union[str, datetime, date]) -> Tuple[int, int, int]: """ 转换日期为年月日元组 Args: date_obj: 日期对象,可以是字符串、datetime或date类型 Returns: Tuple[int, int, int]: 年月日的元组 """ if isinstance(date_obj, str): dt = datetime.strptime(date_obj, "%Y-%m-%d") elif isinstance(date_obj, datetime): dt = date_obj elif isinstance(date_obj, date): dt = datetime.combine(date_obj, datetime.min.time()) else: raise ValueError(f"Unsupported date type: {type(date_obj)}") return dt.year, dt.month, dt.day def _check_birthday(self, recipient: Recipient, today: datetime) -> Tuple[bool, Dict]: """ 检查是否是生日(包括提前提醒) Args: recipient: 收件人信息 today: 当前日期 Returns: Tuple[bool, Dict]: 是否是生日和额外信息 """ try: check_dates = [] for i in range(recipient.reminder_days + 1): check_date = today + timedelta(days=i) check_dates.append(check_date) extra_info = { 'solar_match': False, 'lunar_match': False, 'days_until': 0, 'zodiac': '', # 生肖 'gz_year': '', # 干支纪年 'gz_month': '', # 干支纪月 'gz_day': '', # 干支纪日 'gz_hour': '', # 干支纪时 'lunar_month': '', # 农历月份 'lunar_day': '', # 农历日期 'lunar_festival': '', # 农历节日 'solar_festival': '', # 阳历节日 'solar_term': '', # 节气 'age': 0, 'week_name': '', # 星期 'constellation': '' # 星座 } # 获取今天的详细信息 year, month, day = self._convert_to_date_parts(today) today_solar = Solar.fromYmd(year, month, day) today_lunar = today_solar.getLunar() # 填充当天信息 extra_info.update({ 'gz_year': today_lunar.getYearInGanZhi(), 'gz_month': today_lunar.getMonthInGanZhi(), 'gz_day': today_lunar.getDayInGanZhi(), 'gz_hour': today_lunar.getTimeInGanZhi(), 'lunar_month': f"{today_lunar.getMonthInChinese()}月", 'lunar_day': today_lunar.getDayInChinese(), 'week_name': today_solar.getWeekInChinese(), 'constellation': today_solar.getXingZuo(), }) # 获取节日信息 lunar_festivals = today_lunar.getFestivals() if lunar_festivals: extra_info['lunar_festival'] = '、'.join(lunar_festivals) solar_festivals = today_solar.getFestivals() if solar_festivals: extra_info['solar_festival'] = '、'.join(solar_festivals) # 获取节气 term = today_lunar.getJieQi() if term: extra_info['solar_term'] = term # 检查阳历生日 if recipient.solar_birthday: try: birth_year, birth_month, birth_day = self._convert_to_date_parts( recipient.solar_birthday) for i, check_date in enumerate(check_dates): year, month, day = self._convert_to_date_parts(check_date) if month == birth_month and day == birth_day: extra_info['solar_match'] = True extra_info['days_until'] = i extra_info['age'] = year - birth_year break except ValueError as e: logger.error(f"Invalid solar birthday format for {recipient.name}: {e}") # 检查农历生日 if recipient.lunar_birthday: try: birth_year, birth_month, birth_day = self._convert_to_date_parts( recipient.lunar_birthday) for i, check_date in enumerate(check_dates): year, month, day = self._convert_to_date_parts(check_date) check_solar = Solar.fromYmd(year, month, day) check_lunar = check_solar.getLunar() if (check_lunar.getMonth() == birth_month and check_lunar.getDay() == birth_day): extra_info['lunar_match'] = True extra_info['days_until'] = i extra_info['age'] = year - birth_year break except ValueError as e: logger.error(f"Invalid lunar birthday format for {recipient.name}: {e}") # 如果是生日,添加生肖和其他信息 if extra_info['solar_match'] or extra_info['lunar_match']: try: # 获取生肖和其他信息 if recipient.lunar_birthday: year, month, day = self._convert_to_date_parts( recipient.lunar_birthday) else: year, month, day = self._convert_to_date_parts( recipient.solar_birthday) birth_solar = Solar.fromYmd(year, month, day) birth_lunar = birth_solar.getLunar() extra_info['zodiac'] = birth_lunar.getYearShengXiao() except Exception as e: logger.error(f"Failed to get zodiac info for {recipient.name}: {e}") return (extra_info['solar_match'] or extra_info['lunar_match']), extra_info except Exception as e: logger.error(f"Error checking birthday for {recipient.name}: {e}") return False, {}