个性化文化日历如何保证同日结果可复用:日期规范化、缓存与版本
个性化文化日历如何保证同日结果可复用,关键不是完成一次调用,而是让输入口径、处理状态和结果证据可以复核。本文围绕“如何统一北京时间日期、出生资料版本和缓存键,构建可复用的每日文化日历”给出一套面向真实业务流程的实现方式。
个性化文化日历如何保证同日结果可复用,关键不是完成一次调用,而是让输入口径、处理状态和结果证据可以复核。本文围绕“如何统一北京时间日期、出生资料版本和缓存键,构建可复用的每日文化日历”给出一套面向真实业务流程的实现方式。
问题与结果
同一资料版本、目标日期和规则版本得到稳定缓存键,历史结果不会被后续生成静默覆盖。
适用场景
- 个性化每日文化日历
- 内容订阅和历史查询
- 文化类组件与小程序
实现前先确定边界
- 目标日期必须先统一到 Asia/Shanghai
- 缓存键包含资料、日期和规则版本
- SSE 完成事件与同步 JSON 必须落到同一结果版本
可验证工作流

API 编排与职责
| 步骤 | 接口 | 请求方式 | 用途 |
|---|---|---|---|
| 生成每日内容 | 八字每日趋势解读 | POST | 返回目标日期的基础历法信息和每日文化解读 |
| 查询异步任务 | 异步任务状态查询 | GET | 后台预生成次日或批量内容 |
接口地址:
POST https://api.gugudata.com/ai/bazi-daily-insight
最小可运行实现
curl -X POST \
"https://api.gugudata.com/ai/bazi-daily-insight?appkey=YOUR_APPKEY&responseMode=sync&streaming=false" \
-H "Content-Type: application/json" \
-d '{
"profile": {
"gender": "女",
"calendarType": "公历",
"birthDate": "1992-06-15",
"birthTime": "09:20:00",
"birthPlace": "江苏苏州",
"isLeapMonth": false,
"language": "zh-CN"
},
"targetDate": "2026-08-22"
}'
name 是可选字段。除非产品确实需要称呼建议,否则不传姓名更符合隐私最小化原则。
农历输入必须把年月日理解为农历日期,并只在真实闰月设置 isLeapMonth=true。例如 2025 年闰六月初一:
{
"profile": {
"gender": "女",
"calendarType": "农历",
"birthDate": "2025-06-01",
"birthTime": "09:20:00",
"isLeapMonth": true,
"language": "zh-CN"
},
"targetDate": "2026-08-22"
}
公历请求不能误传 isLeapMonth=true,非闰月年份也不能伪造闰月;这些情况会返回业务码 501。
服务端应显式构造缓存键:
import hashlib
import json
def build_daily_cache_key(profile: dict, target_date: str) -> str:
"""Build a stable cache key for one profile and target date."""
canonical = {
"profile": profile,
"targetDate": target_date,
"contractVersion": "v1",
}
raw = json.dumps(
canonical,
ensure_ascii=False,
sort_keys=True,
separators=(",", ":"),
)
return hashlib.sha256(raw.encode("utf-8")).hexdigest()
缓存键不能只使用用户 ID。用户修改出生时间、历法或语言后,旧内容不应继续命中。
日期边界设计
targetDate 使用 YYYY-MM-DD。未传时,服务端按北京时间当天处理,但生产系统仍建议显式传入日期,便于日志、缓存和测试复现。
| 场景 | 建议 |
|---|---|
| 用户主动查询某天 | 显式传入用户选择的 targetDate |
| 每日零点更新 | 调度任务按 Asia/Shanghai 生成目标日期 |
| 次日内容预生成 | 在任务记录中同时保存创建时间和目标日期 |
| 历史回看 | 读取已有版本,不重新标记为今日结果 |
前端显示的日期、接口请求日期、缓存键和历史记录日期必须一致。需要单独核对农历、节气或日期边界时,可以读取 传统历法宜忌参考,并把它作为独立事实来源记录。
结果怎么组织
基础数据区建议展示:
排盘基础.输入信息的规范化结果;排盘基础.历法换算的公历时间、农历日期、生肖与时区;排盘基础.四柱的年柱、月柱、日柱和时柱;排盘基础.八字的可展示组合;目标日期的农历、干支、生肖、星座和节气。
文化解读区按每日主题、事业学习、关系沟通、生活节奏和行动提醒组织。页面可以提供收藏、复制和加入个人待办,但不能自动把文化解读变成必须执行的日程。
响应模式选择
前台交互可使用 SSE,让用户逐步看到内容;服务端定时任务更适合 responseMode=task。如果应用只需要结构化结果,使用同步 JSON 最简单。
SSE 断线后不应把不完整文本写入正式历史记录。只有收到 type=done 且 done.result 同时包含完整基础数据、六部分文化解读和免责声明后,才能持久化;随后出现的 [DONE] 仅表示事件流结束。异步任务也只有进入 SUCCEEDED 并取得 Data.result 后,才能标记为已生成。
失败分类与降级
出生资料错误属于输入问题,目标日期超出范围或格式错误也应在调用前处理。接口限流或任务失败时,页面可以展示“暂未生成”,但不能回退到其他日期内容且不标记日期。
| 业务码 | HTTP | 处理建议 |
|---|---|---|
| 501 | 400 | 修正日期、时间、历法、闰月或响应模式 |
| 502 | 429 | 按退避策略重试 |
| 503 | 403 | 检查订单有效期 |
| 504 | 401 | 检查 AppKey 是否缺失或无效 |
| 505 | 403 | 补充调用额度 |
| 900 | 500 | 记录请求时间并稍后重试 |
| 901 | 503 | 依赖暂不可用,不保存或缓存当前结果 |
如果用户修改个人资料,需要使未来缓存和当前结果同时失效。已保存的历史版本可以保留,但应显示当时使用的资料快照。
隐私最小化
仅收集完成排盘所需的字段。姓名和出生地点均为可选项;没有明确业务用途时不要传递。日志、错误追踪、分析事件和缓存键不得记录 AppKey、姓名或完整出生资料,运维排查应使用请求 ID、接口标识、业务码和脱敏后的日期范围。
数据契约与留痕
| 字段 | 作用 |
|---|---|
profile_version |
输入、规则或产物版本,变更时保留旧版本 |
target_date |
带时区的采样或生成时间 |
timezone |
业务数据字段,保存来源、口径和缺失状态 |
cache_key |
业务数据字段,保存来源、口径和缺失状态 |
request_id |
稳定业务标识,用于关联记录和请求追踪 |
result_version |
输入、规则或产物版本,变更时保留旧版本 |
generated_at |
带时区的采样或生成时间 |
delivery_status |
显式状态或原因,禁止以空值代替失败 |
重试应新增尝试记录,不覆盖最后一次失败。派生结果必须关联输入版本、生成时间和业务状态。
验收清单
- 午夜和跨日请求使用明确日期口径
- 缓存命中不会跳过版本检查
- 历史记录能还原当时使用的资料版本
能力边界
每日趋势和历法内容仅作文化娱乐参考,不应用于替代医疗、财务或其他专业判断。
示例中的 YOUR_APPKEY 仅为占位符。真实密钥只能放在服务端环境变量或密钥管理系统中。