基于Python+Flask实现农历转换API实战指南
针对国内业务系统中广泛使用的农历日期展示与计算需求,本文介绍如何使用 Python 的 lunar-python 库结合 Flask 框架,快速搭建一套支持公历转农历、农历反推公历(含闰月处理)、实时查询及干支生肖节气的 REST API。服务覆盖 1900 至 2100 年,结构清晰且无需外部依赖,可直接集成至日历应用或小程序后端。
环境准备与核心数据结构
在国内日历、黄历、命理及本地化系统中,农历(阴历)的精准转换是常见刚需。为实现高效稳定的日期处理,本文选用成熟且权威的纯 Python 算法库 lunar-python,配合轻量级 Web 框架 Flask 进行封装。该组合无外部系统依赖,原生支持干支、生肖、节气、扩展节日及闰月(负数月份标识),非常适合内部工具服务或独立部署。
第 1 步:安装依赖库
在项目环境中执行以下命令安装核心组件:
pip install lunar-python flask
注:安装包名为 lunar-python,但在 Python 代码中需通过 import lunar_python 调用。
第 2 步:封装统一农历数据格式
为方便前端或其他业务系统直接使用,首先对算法库的原始返回值进行标准化清洗。重点处理闰月标识(getMonth()<0 为闰月)以及传统节日与扩展节日的分类:
def format_lunar(lunar):
"""统一格式化农历信息(完全适配 lunar_python 最新版)"""
month = lunar.getMonth() # 可能为负数(闰月)
is_leap_month = month < 0
abs_month = abs(month)
festivals = lunar.getFestivals() # 标准农历节日
other_festivals = lunar.getOtherFestivals() # 其他扩展节日
return {
"lunar_year": lunar.getYear(),
"lunar_month": abs_month,
"lunar_day": lunar.getDay(),
"is_leap_month": is_leap_month,
"chinese_string": lunar.toFullString(),
"ganzhi_year": lunar.getYearInChinese(),
"ganzhi_month": lunar.getMonthInChinese(),
"ganzhi_day": lunar.getDayInChinese(),
"shengxiao": lunar.getYearShengXiao(),
"jieqi": lunar.getJieQi() if lunar.getJieQi() else None,
"festivals": festivals if festivals else None,
"other_festivals": other_festivals if other_festivals else None
}
REST API 接口开发与逻辑
基于 Flask 路由机制,依次定义四个核心端点。所有接口均包含基础的异常捕获,确保非法输入时返回 400 状态码及详细错误提示。
第 3 步:实现公历转农历接口
通过 GET 请求接收年月日参数,调用 Solar.fromYmd() 转为阳历实例后获取农历:
@app.route('/api/to_lunar', methods=['GET'])
def to_lunar():
try:
year = int(request.args.get('year'))
month = int(request.args.get('month'))
day = int(request.args.get('day'))
solar = Solar.fromYmd(year, month, day)
lunar = solar.getLunar()
return jsonify({
"success": True,
"solar_date": f"{year}-{month:02d}-{day:02d}",
"lunar": format_lunar(lunar)
})
except Exception as e:
app.logger.error(f"Error in to_lunar: {str(e)}")
return jsonify({"success": False, "error": str(e)}), 400
测试请求示例:GET /api/to_lunar?year=2025&month=2&day=1
第 4 步:实现农历转公历接口(闰月适配)
反向转换需额外处理闰月参数。在 lunar_python 规范中,传入负数月份即可代表闰月:
@app.route('/api/to_solar', methods=['GET'])
def to_solar():
try:
year = int(request.args.get('year'))
month = int(request.args.get('month'))
day = int(request.args.get('day'))
leap = request.args.get('leap', 'false').lower() in ('true', '1', 'yes')
lunar_month = -month if leap else month
lunar = Lunar.fromYmd(year, lunar_month, day)
solar = lunar.getSolar()
return jsonify({
"success": True,
"lunar": format_lunar(lunar),
"solar_date": solar.toYmd()
})
except Exception as e:
app.logger.error(f"Error in to_solar: {str(e)}")
return jsonify({"success": False, "error": str(e)}), 400
第 5 步:添加当前农历查询接口
适用于首页日签、黄历看板等场景。利用 datetime.now() 获取服务器当前时间并解析:
@app.route('/api/today_lunar', methods=['GET'])
def today_lunar():
try:
now = datetime.now()
today_solar = Solar.fromDate(now)
today_lunar = today_solar.getLunar()
return jsonify({
"success": True,
"solar_date": today_solar.toYmd(),
"solar_datetime": today_solar.toYmdHms(),
"timestamp": now.isoformat(),
"lunar": format_lunar(today_lunar)
})
except Exception as e:
tb = traceback.format_exc()
app.logger.error(f"Error in today_lunar: {str(e)}\n{tb}")
return jsonify({"success": False, "error": "Internal Server Error", "detail": str(e), "traceback": tb}), 500
服务部署与运行配置
第 6 步:启动服务并访问验证
将上述路由函数整合至同一文件中,添加入口启动代码。开发阶段启用调试模式便于查看报错栈:
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5006, debug=True)
启动后访问 http://localhost:5006/ 将返回健康检查 JSON,包含各接口路径说明。实际生产环境中,建议移除 debug=True 并将 host 绑定至指定内网 IP,同时配置 Nginx 反向代理或 Gunicorn 承载高并发请求。
常见问题与排查建议
- 闰月识别失败:确保
to_solar接口的leap参数正确传递布尔值,并在代码中转换为负数月份。Lunar.fromYmd(2025, -2, 5)等效于闰二月。 - 时区偏差:
datetime.now()依赖服务器系统时区。若业务跨地域,建议在入口处显式指定时区(如zoneinfo.ZoneInfo("Asia/Shanghai"))以保证农历日切分准确。 - 日志未持久化:示例代码使用
app.logger,默认仅输出至控制台。生产环境建议通过logging.config.dictConfig配置文件轮转策略。
总结
本文基于 lunar-python + Flask 实现了一套功能完整、结构清晰、可直接部署的农历转换 API。该方案不依赖外部命令行工具,原生支持闰月解析与干支节气计算,返回的 JSON 结构经过统一清洗,极大降低了前后端联调成本。无论是日历类应用、生日提醒系统还是企业微信/钉钉机器人内部工具,均可平滑接入。以上就是基于Python+Flask实现农历转换API实战指南的详细内容,更多关于Python农历转换API与内部服务集成的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













