news 2026/10/10 22:40:11

基于 Flask + lunar-python 的农历转换 API 实战(公历 ↔ 农历 / 干支 / 生肖 / 节日)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于 Flask + lunar-python 的农历转换 API 实战(公历 ↔ 农历 / 干支 / 生肖 / 节日)

在国内业务系统中,农历(阴历)仍然被广泛使用,例如:

  • 农历生日、纪念日
  • 传统节日(春节、除夕、中秋)
  • 日历 / 黄历 / 命理类应用
  • 本地化系统展示

本文基于lunar-python农历算法库,使用Flask封装了一套完整、可直接部署的农历转换 REST API,支持:

  • ✅ 公历 → 农历
  • ✅ 农历 → 公历(支持闰月)
  • ✅ 当前农历日期查询
  • ✅ 干支、生肖、节气、节日
  • ✅ 完整中文描述

支持时间范围:1900 – 2100 年


一、技术选型说明

1️⃣ lunar-python

选择lunar-python的原因:

  • 农历算法成熟、权威
  • API 设计清晰
  • 支持干支、生肖、节气、节日
  • 支持闰月(负数月份表示)
  • 纯 Python,无外部依赖
pipinstalllunar-python

2️⃣ Flask

  • 轻量
  • 易于部署
  • 非常适合工具型 API / 内部服务
pipinstallflask

二、API 设计说明

本示例实现了 4 个接口:

接口说明
/api/to_lunar公历 → 农历
/api/to_solar农历 → 公历(支持闰月)
/api/today_lunar获取当前农历
/服务状态 & 接口说明

三、核心设计:统一农历数据结构

为了方便前端或其他系统使用,先对lunar-python的返回结果进行统一格式化。

农历信息格式化函数

defformat_lunar(lunar):"""统一格式化农历信息(完全适配 lunar_python 最新版)"""month=lunar.getMonth()# 可能为负数(闰月)is_leap_month=month<0abs_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(),"full_info":lunar.toFullString(),"ganzhi_year":lunar.getYearInChinese(),"ganzhi_month":lunar.getMonthInChinese(),"ganzhi_day":lunar.getDayInChinese(),"shengxiao":lunar.getYearShengXiao(),"jieqi":lunar.getJieQi()iflunar.getJieQi()elseNone,"festivals":festivalsiffestivalselseNone,"other_festivals":other_festivalsifother_festivalselseNone}

设计说明

  • 闰月判断:month < 0

  • 节日区分:

    • getFestivals():传统节日(春节、除夕)
    • getOtherFestivals():扩展节日
  • 输出结构稳定,方便前端直接使用


四、公历 → 农历 API

接口定义

GET /api/to_lunar

参数

参数说明
year公历年
month公历月
day公历日

代码实现

@app.route('/api/to_lunar',methods=['GET'])defto_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()returnjsonify({"success":True,"solar_date":f"{year}-{month:02d}-{day:02d}","lunar":format_lunar(lunar)})exceptExceptionase:returnjsonify({"success":False,"error":str(e)}),400

示例请求

/api/to_lunar?year=2025&month=2&day=1

五、农历 → 公历 API(支持闰月)

接口定义

GET /api/to_solar

参数

参数说明
year农历年
month农历月
day农历日
leap是否闰月(true / false)

关键点:闰月处理

lunar_month=-monthifleapelsemonth

这是lunar-python的标准用法。

代码实现

@app.route('/api/to_solar',methods=['GET'])defto_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=-monthifleapelsemonth lunar=Lunar.fromYmd(year,lunar_month,day)solar=lunar.getSolar()returnjsonify({"success":True,"lunar":format_lunar(lunar),"solar_date":solar.toYmd()})exceptExceptionase:returnjsonify({"success":False,"error":str(e)}),400

六、获取当前农历日期 API

接口定义

GET /api/today_lunar

代码实现

@app.route('/api/today_lunar',methods=['GET'])deftoday_lunar():try:now=datetime.now()today_solar=Solar.fromDate(now)today_lunar=today_solar.getLunar()returnjsonify({"success":True,"solar_date":today_solar.toYmd(),"solar_datetime":today_solar.toYmdHms(),"timestamp":now.isoformat(),"lunar":format_lunar(today_lunar)})exceptExceptionase:returnjsonify({"success":False,"error":str(e)}),500

适合:

  • 首页日历
  • 今日农历展示
  • 黄历 / 日签应用

七、服务启动与运行

if__name__=='__main__':app.run(host='0.0.0.0',port=5006,debug=True)

启动后访问:

http://localhost:5006/

即可看到接口说明。


八、返回 JSON 示例(简化)

{"lunar_year":2024,"lunar_month":12,"lunar_day":4,"is_leap_month":false,"chinese_string":"甲辰年 腊月初四","shengxiao":"龙","festivals":["春节"]}

完整代码

from flaskimportFlask, request, jsonify from lunar_pythonimportSolar, Lunar from datetimeimportdatetimeimporttraceback app=Flask(__name__)def format_lunar(lunar):"""统一格式化农历信息(完全适配 lunar_python 最新版)""" month=lunar.getMonth()# 可能为负数(闰月)is_leap_month=month<0abs_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(),"full_info":lunar.toFullString(),"ganzhi_year":lunar.getYearInChinese(),"ganzhi_month":lunar.getMonthInChinese(),"ganzhi_day":lunar.getDayInChinese(),"shengxiao":lunar.getYearShengXiao(),"jieqi":lunar.getJieQi()iflunar.getJieQi()elseNone,"festivals":festivalsiffestivalselseNone,# 传统农历节日列表"other_festivals":other_festivalsifother_festivalselseNone# 其他节日}@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()returnjsonify({"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)}\n{traceback.format_exc()}")returnjsonify({"success":False,"error":str(e),"detail":str(e)}),400@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=-monthifleapelsemonth lunar=Lunar.fromYmd(year, lunar_month, day)solar=lunar.getSolar()returnjsonify({"success":True,"lunar":format_lunar(lunar),"solar_date":solar.toYmd()})except Exception as e: app.logger.error(f"Error in to_solar: {str(e)}\n{traceback.format_exc()}")returnjsonify({"success":False,"error":str(e),"detail":str(e)}),400@app.route('/api/today_lunar',methods=['GET'])def today_lunar(): try: app.logger.info("Calling /api/today_lunar")now=datetime.now()today_solar=Solar.fromDate(now)app.logger.info(f"Today solar: {today_solar.toYmd()} {today_solar.toYmdHms()}")today_lunar=today_solar.getLunar()returnjsonify({"success":True,"solar_date":today_solar.toYmd(),"solar_datetime":today_solar.toYmdHms(),"timestamp":now.isoformat(),"lunar":format_lunar(today_lunar)})except Exception as e: error_msg=str(e)tb=traceback.format_exc()app.logger.error(f"Error in today_lunar: {error_msg}\n{tb}")returnjsonify({"success":False,"error":"Internal Server Error","detail":error_msg,"traceback":tb}),500@app.route('/',methods=['GET'])def home():returnjsonify({"message":"Lunar Calendar API is running! (lunar_python fully adapted)","current_time":datetime.now().isoformat(),"endpoints":{"to_lunar":"/api/to_lunar?year=2025&month=12&day=24","to_solar":"/api/to_solar?year=2025&month=11&day=5&leap=false","today_lunar":"/api/today_lunar"}})if__name__=='__main__':app.run(host='0.0.0.0',port=5006,debug=True)

九、适用场景

  • 📅 日历 / 黄历系统
  • 🎂 农历生日管理
  • 🧧 中国本土化应用
  • 🌐 Web / 小程序后端
  • 🧰 内部工具 API

十、总结

本文基于lunar-python + Flask实现了一套:

功能完整、结构清晰、可直接部署的农历转换 API

特点:

  • 不依赖外部命令
  • 支持闰月
  • 返回结构友好
  • 易于扩展

非常适合用于实际生产项目。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/9 13:36:42

终极中文文本标注工具:从零开始快速上手指南

终极中文文本标注工具&#xff1a;从零开始快速上手指南 【免费下载链接】Chinese-Annotator Annotator for Chinese Text Corpus (UNDER DEVELOPMENT) 中文文本标注工具 项目地址: https://gitcode.com/gh_mirrors/ch/Chinese-Annotator 在当今人工智能快速发展的时代&…

作者头像 李华
网站建设 2026/10/9 13:36:47

【开题答辩全过程】以 基于Python的豆瓣图书聚类分析为例,包含答辩的问题和答案

个人简介一名14年经验的资深毕设内行人&#xff0c;语言擅长Java、php、微信小程序、Python、Golang、安卓Android等开发项目包括大数据、深度学习、网站、小程序、安卓、算法。平常会做一些项目定制化开发、代码讲解、答辩教学、文档编写、也懂一些降重方面的技巧。感谢大家的…

作者头像 李华
网站建设 2026/10/9 13:36:53

麦田软件完整下载指南:快速获取与安装全流程

麦田软件完整下载指南&#xff1a;快速获取与安装全流程 【免费下载链接】麦田软件资源下载 本仓库提供了一个名为“麦田软件.zip”的资源文件下载。该文件包含了麦田软件的相关资源&#xff0c;适用于需要使用麦田软件的用户 项目地址: https://gitcode.com/open-source-too…

作者头像 李华
网站建设 2026/10/10 17:55:43

transformer模型详解(三):位置编码实现与改进

Transformer模型中的位置编码&#xff1a;从原理到工程实践 在构建现代自然语言处理系统时&#xff0c;一个看似微小的设计选择——如何告诉模型“这个词出现在第几个位置”——却可能深刻影响整个系统的性能上限。Transformer 架构之所以能取代 RNN 成为主流&#xff0c;除了自…

作者头像 李华
网站建设 2026/10/8 19:00:05

如何快速掌握Files文件管理器:GitHub仓库管理的终极指南

还记得第一次接触Git时那种手足无措的感觉吗&#xff1f;命令行里密密麻麻的指令&#xff0c;分支合并时的冲突警告&#xff0c;每一次提交都像在走钢丝。直到我发现了Files文件管理器&#xff0c;这个专门为Windows设计的现代化文件管理工具&#xff0c;它让GitHub仓库管理变得…

作者头像 李华
网站建设 2026/10/9 3:33:35

RPCS3模拟器汉化完全攻略:打造专属中文游戏世界

嘿&#xff0c;游戏玩家们&#xff01;是不是早就想在大屏幕上重温那些经典的PS3独占游戏了&#xff1f;但面对满屏的日文或英文&#xff0c;是不是有点头大&#xff1f;别担心&#xff0c;今天咱们就来聊聊如何让RPCS3模拟器说中文&#xff0c;让你彻底告别语言障碍&#xff0…

作者头像 李华