基于Python+Flask實現(xiàn)農(nóng)歷轉(zhuǎn)換API實戰(zhàn)指南
在國內(nèi)業(yè)務(wù)系統(tǒng)中,農(nóng)歷(陰歷) 仍然被廣泛使用,例如:
- 農(nóng)歷生日、紀(jì)念日
- 傳統(tǒng)節(jié)日(春節(jié)、除夕、中秋)
- 日歷 / 黃歷 / 命理類應(yīng)用
- 本地化系統(tǒng)展示
本文基于 lunar-python 農(nóng)歷算法庫,使用 Flask 封裝了一套 完整、可直接部署的農(nóng)歷轉(zhuǎn)換 REST API,支持:
- 公歷 → 農(nóng)歷
- 農(nóng)歷 → 公歷(支持閏月)
- 當(dāng)前農(nóng)歷日期查詢
- 干支、生肖、節(jié)氣、節(jié)日
- 完整中文描述
支持時間范圍:1900 – 2100 年
一、技術(shù)選型說明
lunar-python
選擇 lunar-python 的原因:
- 農(nóng)歷算法成熟、權(quán)威
- API 設(shè)計清晰
- 支持干支、生肖、節(jié)氣、節(jié)日
- 支持閏月(負數(shù)月份表示)
- 純 Python,無外部依賴
pip install lunar-python
Flask
- 輕量
- 易于部署
- 非常適合工具型 API / 內(nèi)部服務(wù)
pip install flask
二、API 設(shè)計說明
本示例實現(xiàn)了 4 個接口:
| 接口 | 說明 |
|---|---|
| /api/to_lunar | 公歷 → 農(nóng)歷 |
| /api/to_solar | 農(nóng)歷 → 公歷(支持閏月) |
| /api/today_lunar | 獲取當(dāng)前農(nóng)歷 |
| / | 服務(wù)狀態(tài) & 接口說明 |
三、核心設(shè)計:統(tǒng)一農(nóng)歷數(shù)據(jù)結(jié)構(gòu)
為了方便前端或其他系統(tǒng)使用,先對 lunar-python 的返回結(jié)果進行統(tǒng)一格式化。
農(nóng)歷信息格式化函數(shù)
def format_lunar(lunar):
"""統(tǒng)一格式化農(nóng)歷信息(完全適配 lunar_python 最新版)"""
month = lunar.getMonth() # 可能為負數(shù)(閏月)
is_leap_month = month < 0
abs_month = abs(month)
festivals = lunar.getFestivals() # 標(biāo)準(zhǔn)農(nóng)歷節(jié)日
other_festivals = lunar.getOtherFestivals() # 其他擴展節(jié)日
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() if lunar.getJieQi() else None,
"festivals": festivals if festivals else None,
"other_festivals": other_festivals if other_festivals else None
}
設(shè)計說明
閏月判斷:month < 0
節(jié)日區(qū)分:
- getFestivals():傳統(tǒng)節(jié)日(春節(jié)、除夕)
- getOtherFestivals():擴展節(jié)日
輸出結(jié)構(gòu)穩(wěn)定,方便前端直接使用
四、公歷 → 農(nóng)歷 API
接口定義
GET /api/to_lunar
參數(shù)
| 參數(shù) | 說明 |
|---|---|
| year | 公歷年 |
| month | 公歷月 |
| day | 公歷日 |
代碼實現(xiàn)
@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:
return jsonify({
"success": False,
"error": str(e)
}), 400
示例請求
/api/to_lunar?year=2025&month=2&day=1
五、農(nóng)歷 → 公歷 API(支持閏月)
接口定義
GET /api/to_solar
參數(shù)
| 參數(shù) | 說明 |
|---|---|
| year | 農(nóng)歷年 |
| month | 農(nóng)歷月 |
| day | 農(nóng)歷日 |
| leap | 是否閏月(true / false) |
關(guān)鍵點:閏月處理
lunar_month = -month if leap else month
這是 lunar-python 的標(biāo)準(zhǔn)用法。
代碼實現(xiàn)
@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:
return jsonify({
"success": False,
"error": str(e)
}), 400
六、獲取當(dāng)前農(nóng)歷日期 API
接口定義
GET /api/today_lunar
代碼實現(xiàn)
@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:
return jsonify({
"success": False,
"error": str(e)
}), 500
適合:
- 首頁日歷
- 今日農(nóng)歷展示
- 黃歷 / 日簽應(yīng)用
七、服務(wù)啟動與運行
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": ["春節(jié)"]
}
九、完整代碼
from flask import Flask, request, jsonify
from lunar_python import Solar, Lunar
from datetime import datetime
import traceback
app = Flask(__name__)
def format_lunar(lunar):
"""統(tǒng)一格式化農(nóng)歷信息(完全適配 lunar_python 最新版)"""
month = lunar.getMonth() # 可能為負數(shù)(閏月)
is_leap_month = month < 0
abs_month = abs(month)
festivals = lunar.getFestivals() # 標(biāo)準(zhǔn)農(nóng)歷節(jié)日(如春節(jié)、除夕)
other_festivals = lunar.getOtherFestivals() # 其他擴展節(jié)日
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() if lunar.getJieQi() else None,
"festivals": festivals if festivals else None, # 傳統(tǒng)農(nóng)歷節(jié)日列表
"other_festivals": other_festivals if other_festivals else None # 其他節(jié)日
}
@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)}\n{traceback.format_exc()}")
return jsonify({
"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 = -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)}\n{traceback.format_exc()}")
return jsonify({
"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()
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:
error_msg = str(e)
tb = traceback.format_exc()
app.logger.error(f"Error in today_lunar: {error_msg}\n{tb}")
return jsonify({
"success": False,
"error": "Internal Server Error",
"detail": error_msg,
"traceback": tb
}), 500
@app.route('/', methods=['GET'])
def home():
return jsonify({
"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)
十、適用場景
日歷 / 黃歷系統(tǒng)
農(nóng)歷生日管理
中國本土化應(yīng)用
Web / 小程序后端
內(nèi)部工具 API
總結(jié)
本文基于 lunar-python + Flask 實現(xiàn)了一套功能完整、結(jié)構(gòu)清晰、可直接部署的農(nóng)歷轉(zhuǎn)換 API
特點:
- 不依賴外部命令
- 支持閏月
- 返回結(jié)構(gòu)友好
- 易于擴展
非常適合用于實際生產(chǎn)項目。
到此這篇關(guān)于基于Python+Flask實現(xiàn)農(nóng)歷轉(zhuǎn)換API實戰(zhàn)指南的文章就介紹到這了,更多相關(guān)Python農(nóng)歷轉(zhuǎn)換API內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python數(shù)學(xué)建模學(xué)習(xí)模擬退火算法多變量函數(shù)優(yōu)化示例解析
模擬退火算法借鑒了統(tǒng)計物理學(xué)的思想,是一種簡單、通用的啟發(fā)式優(yōu)化算法,并在理論上具有概率性全局優(yōu)化性能,因而在科研和工程中得到了廣泛的應(yīng)用2021-10-10
Python協(xié)程asyncio模塊的演變及高級用法
網(wǎng)上很多關(guān)于Python協(xié)程asyncio模塊的教程都是基于老版Python的, 本文將以對比方式展示新老Python版本下協(xié)程的寫法有什么不同并總結(jié)了asyncio的一些高級用法, 包括如何獲取協(xié)程任務(wù)執(zhí)行結(jié)果,gather和wait方法的區(qū)別以及如何給任務(wù)添加回調(diào)函數(shù)。2021-05-05
Pytorch修改ResNet模型全連接層進行直接訓(xùn)練實例
在本篇文章里小編給大家整理的是關(guān)于Pytorch修改ResNet模型全連接層進行直接訓(xùn)練相關(guān)知識點,有需要的朋友們參考下。2019-09-09
詳解Python中的時間格式的讀取與轉(zhuǎn)換(time模塊)
這篇文章主要介紹了Python中的時間格式的讀取與轉(zhuǎn)換(time模塊),文末給大家介紹了python的時間獲取與轉(zhuǎn)化:time模塊和datetime模塊的相關(guān)知識,需要的朋友可以參考下2023-05-05
python中子類與父類的關(guān)系基礎(chǔ)知識點
在本篇文章里小編給大家整理的是一篇關(guān)于python中子類與父類的關(guān)系基礎(chǔ)知識點內(nèi)容,對此有興趣的朋友們可以學(xué)習(xí)下。2021-02-02
200個Python?標(biāo)準(zhǔn)庫總結(jié)
這篇文章主要給大家分享了200個Python?標(biāo)準(zhǔn)庫總結(jié),主要對文本、數(shù)據(jù)類型、數(shù)學(xué)等多個類型總結(jié),既有一定的參考價值,需要的小伙伴可以參考一下2022-01-01

