We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/spyfree/mingli-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server
"""
生辰信息数据模型
"""
from dataclasses import dataclass
from datetime import datetime
from typing import Optional
@dataclass
class BirthInfo:
"""生辰信息数据类"""
date: str # YYYY-MM-DD格式
time_index: int # 0-12,对应子时到晚子时
gender: str # "男" 或 "女"
calendar: str = "solar" # "solar" 或 "lunar"
is_leap_month: bool = False # 是否闰月(仅农历有效)
# 真太阳时支持(可选)
longitude: Optional[float] = None # 出生地经度(东经为正,西经为负)
latitude: Optional[float] = None # 出生地纬度(北纬为正,南纬为负)
use_solar_time: bool = False # 是否使用真太阳时修正
birth_hour: Optional[int] = None # 出生时刻小时(0-23),用于真太阳时精确计算
birth_minute: Optional[int] = None # 出生时刻分钟(0-59),用于真太阳时精确计算
def __post_init__(self):
"""验证数据有效性"""
if not 0 <= self.time_index <= 12:
raise ValueError("时辰序号必须在0-12之间")
if self.gender not in ["男", "女"]:
raise ValueError("性别必须是'男'或'女'")
if self.calendar not in ["solar", "lunar"]:
raise ValueError("历法类型必须是'solar'或'lunar'")
# 验证日期格式
try:
datetime.strptime(self.date, "%Y-%m-%d")
except ValueError:
raise ValueError("日期格式必须是YYYY-MM-DD")
# 真太阳时验证
if self.use_solar_time:
if self.longitude is None:
raise ValueError("使用真太阳时必须提供经度(longitude)")
if not -180 <= self.longitude <= 180:
raise ValueError("经度必须在-180到180之间")
# 如果提供了纬度,验证范围
if self.latitude is not None and not -90 <= self.latitude <= 90:
raise ValueError("纬度必须在-90到90之间")
# 如果提供了具体时刻,验证范围
if self.birth_hour is not None and not 0 <= self.birth_hour <= 23:
raise ValueError("小时必须在0-23之间")
if self.birth_minute is not None and not 0 <= self.birth_minute <= 59:
raise ValueError("分钟必须在0-59之间")
# 如果使用真太阳时,建议提供具体时刻
if self.birth_hour is None or self.birth_minute is None:
# 这里只是警告,不抛出异常,因为可以使用time_index的中点时间
pass
def to_dict(self) -> dict:
"""转换为字典"""
data = {
"date": self.date,
"time_index": self.time_index,
"gender": self.gender,
"calendar": self.calendar,
"is_leap_month": self.is_leap_month,
}
# 添加真太阳时相关字段(如果存在)
if self.longitude is not None:
data["longitude"] = self.longitude
if self.latitude is not None:
data["latitude"] = self.latitude
if self.use_solar_time:
data["use_solar_time"] = self.use_solar_time
if self.birth_hour is not None:
data["birth_hour"] = self.birth_hour
if self.birth_minute is not None:
data["birth_minute"] = self.birth_minute
return data
@classmethod
def from_dict(cls, data: dict) -> "BirthInfo":
"""从字典创建"""
return cls(
date=data["date"],
time_index=data["time_index"],
gender=data["gender"],
calendar=data.get("calendar", "solar"),
is_leap_month=data.get("is_leap_month", False),
longitude=data.get("longitude"),
latitude=data.get("latitude"),
use_solar_time=data.get("use_solar_time", False),
birth_hour=data.get("birth_hour"),
birth_minute=data.get("birth_minute"),
)
def get_time_range(self) -> str:
"""获取时辰对应的时间段"""
time_ranges = [
"23:00~01:00", # 0 早子时
"01:00~03:00", # 1 丑时
"03:00~05:00", # 2 寅时
"05:00~07:00", # 3 卯时
"07:00~09:00", # 4 辰时
"09:00~11:00", # 5 巳时
"11:00~13:00", # 6 午时
"13:00~15:00", # 7 未时
"15:00~17:00", # 8 申时
"17:00~19:00", # 9 酉时
"19:00~21:00", # 10 戌时
"21:00~23:00", # 11 亥时
"23:00~01:00", # 12 晚子时
]
return time_ranges[self.time_index]
def get_time_name(self) -> str:
"""获取时辰名称"""
time_names = [
"早子时",
"丑时",
"寅时",
"卯时",
"辰时",
"巳时",
"午时",
"未时",
"申时",
"酉时",
"戌时",
"亥时",
"晚子时",
]
return time_names[self.time_index]
def get_adjusted_time_index(self) -> int:
"""
获取真太阳时修正后的时辰序号
如果use_solar_time=True且提供了经度,则根据真太阳时计算时辰序号;
否则返回原始的time_index。
Returns:
修正后的时辰序号(0-12)
Examples:
>>> # 不使用真太阳时
>>> info = BirthInfo(date="2000-08-16", time_index=6, gender="女")
>>> info.get_adjusted_time_index()
6
>>> # 使用真太阳时(乌鲁木齐,经度87.6°,时差约-129分钟)
>>> info = BirthInfo(
... date="2000-08-16", time_index=6, gender="女",
... longitude=87.6, use_solar_time=True,
... birth_hour=12, birth_minute=0
... )
>>> info.get_adjusted_time_index() # 12:00 - 129分钟 ≈ 9:51,仍是巳时(5)
5
"""
if not self.use_solar_time or self.longitude is None:
return self.time_index
# 延迟导入避免循环依赖
from utils.solar_time import adjust_time_index_for_solar_time
# 获取出生时刻
if self.birth_hour is not None and self.birth_minute is not None:
hour = self.birth_hour
minute = self.birth_minute
else:
# 如果没有提供具体时刻,使用时辰的中点时间
hour, minute = self._get_time_index_midpoint()
# 计算真太阳时修正后的时辰
adjusted_index, _, _ = adjust_time_index_for_solar_time(hour, minute, self.longitude)
return adjusted_index
def _get_time_index_midpoint(self) -> tuple[int, int]:
"""
获取时辰的中点时间(小时,分钟)
Returns:
(小时, 分钟) 元组
Examples:
>>> info = BirthInfo(date="2000-08-16", time_index=6, gender="女")
>>> info._get_time_index_midpoint()
(12, 0) # 午时中点
"""
# 时辰中点映射(小时, 分钟)
midpoints = [
(0, 0), # 0 早子时 (23:00-01:00) -> 00:00
(2, 0), # 1 丑时 (01:00-03:00) -> 02:00
(4, 0), # 2 寅时 (03:00-05:00) -> 04:00
(6, 0), # 3 卯时 (05:00-07:00) -> 06:00
(8, 0), # 4 辰时 (07:00-09:00) -> 08:00
(10, 0), # 5 巳时 (09:00-11:00) -> 10:00
(12, 0), # 6 午时 (11:00-13:00) -> 12:00
(14, 0), # 7 未时 (13:00-15:00) -> 14:00
(16, 0), # 8 申时 (15:00-17:00) -> 16:00
(18, 0), # 9 酉时 (17:00-19:00) -> 18:00
(20, 0), # 10 戌时 (19:00-21:00) -> 20:00
(22, 0), # 11 亥时 (21:00-23:00) -> 22:00
(0, 0), # 12 晚子时 (23:00-01:00) -> 00:00(次日)
]
return midpoints[self.time_index]
def get_solar_time_info(self) -> Optional[str]:
"""
获取真太阳时信息(用于日志和调试)
Returns:
格式化的真太阳时信息字符串,如果不使用真太阳时则返回None
Examples:
>>> info = BirthInfo(
... date="2000-08-16", time_index=6, gender="女",
... longitude=116.4, use_solar_time=True,
... birth_hour=12, birth_minute=0
... )
>>> print(info.get_solar_time_info())
北京时间: 2000-08-16 12:00
出生地经度: 116.4°E
时差: -14分钟
真太阳时: 2000-08-16 11:46
修正前时辰: 午时 (序号: 6)
修正后时辰: 午时 (序号: 6)
"""
if not self.use_solar_time or self.longitude is None:
return None
# 延迟导入
from utils.solar_time import (
beijing_to_solar_time,
calculate_solar_time_offset,
)
# 获取出生时刻
if self.birth_hour is not None and self.birth_minute is not None:
hour = self.birth_hour
minute = self.birth_minute
else:
hour, minute = self._get_time_index_midpoint()
# 创建临时datetime
birth_datetime = datetime.strptime(self.date, "%Y-%m-%d")
birth_datetime = birth_datetime.replace(hour=hour, minute=minute)
# 计算真太阳时
solar_datetime = beijing_to_solar_time(birth_datetime, self.longitude)
offset = calculate_solar_time_offset(self.longitude)
adjusted_index = self.get_adjusted_time_index()
offset_str = f"+{offset}分钟" if offset > 0 else f"{offset}分钟"
return f"""北京时间: {birth_datetime.strftime('%Y-%m-%d %H:%M')}
出生地经度: {self.longitude}°E
时差: {offset_str}
真太阳时: {solar_datetime.strftime('%Y-%m-%d %H:%M')}
修正前时辰: {self.get_time_name()} (序号: {self.time_index})
修正后时辰: {self._get_time_name_by_index(adjusted_index)} (序号: {adjusted_index})"""
def _get_time_name_by_index(self, index: int) -> str:
"""根据时辰序号获取时辰名称"""
time_names = [
"早子时",
"丑时",
"寅时",
"卯时",
"辰时",
"巳时",
"午时",
"未时",
"申时",
"酉时",
"戌时",
"亥时",
"晚子时",
]
return time_names[index]