基于Python+Flask實(shí)現(xiàn)農(nóng)歷轉(zhuǎn)換API實(shí)戰(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é)日
- 完整中文描述
支持時(shí)間范圍:1900 – 2100 年
一、技術(shù)選型說明
lunar-python
選擇 lunar-python 的原因:
- 農(nóng)歷算法成熟、權(quán)威
- API 設(shè)計(jì)清晰
- 支持干支、生肖、節(jié)氣、節(jié)日
- 支持閏月(負(fù)數(shù)月份表示)
- 純 Python,無外部依賴
pip install lunar-python
Flask
- 輕量
- 易于部署
- 非常適合工具型 API / 內(nèi)部服務(wù)
pip install flask
二、API 設(shè)計(jì)說明
本示例實(shí)現(xiàn)了 4 個(gè)接口:
| 接口 | 說明 |
|---|---|
| /api/to_lunar | 公歷 → 農(nóng)歷 |
| /api/to_solar | 農(nóng)歷 → 公歷(支持閏月) |
| /api/today_lunar | 獲取當(dāng)前農(nóng)歷 |
| / | 服務(wù)狀態(tài) & 接口說明 |
三、核心設(shè)計(jì):統(tǒng)一農(nóng)歷數(shù)據(jù)結(jié)構(gòu)
為了方便前端或其他系統(tǒng)使用,先對 lunar-python 的返回結(jié)果進(jìn)行統(tǒng)一格式化。
農(nóng)歷信息格式化函數(shù)
def format_lunar(lunar):
"""統(tǒng)一格式化農(nóng)歷信息(完全適配 lunar_python 最新版)"""
month = lunar.getMonth() # 可能為負(fù)數(shù)(閏月)
is_leap_month = month < 0
abs_month = abs(month)
festivals = lunar.getFestivals() # 標(biāo)準(zhǔn)農(nóng)歷節(jié)日
other_festivals = lunar.getOtherFestivals() # 其他擴(kuò)展節(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è)計(jì)說明
閏月判斷:month < 0
節(jié)日區(qū)分:
- getFestivals():傳統(tǒng)節(jié)日(春節(jié)、除夕)
- getOtherFestivals():擴(kuò)展節(jié)日
輸出結(jié)構(gòu)穩(wěn)定,方便前端直接使用
四、公歷 → 農(nóng)歷 API
接口定義
GET /api/to_lunar
參數(shù)
| 參數(shù) | 說明 |
|---|---|
| year | 公歷年 |
| month | 公歷月 |
| day | 公歷日 |
代碼實(shí)現(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)鍵點(diǎn):閏月處理
lunar_month = -month if leap else month
這是 lunar-python 的標(biāo)準(zhǔn)用法。
代碼實(shí)現(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
代碼實(shí)現(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ù)啟動(dòng)與運(yùn)行
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5006, debug=True)
啟動(dòng)后訪問: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() # 可能為負(fù)數(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() # 其他擴(kuò)展節(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 實(shí)現(xiàn)了一套功能完整、結(jié)構(gòu)清晰、可直接部署的農(nóng)歷轉(zhuǎn)換 API
特點(diǎn):
- 不依賴外部命令
- 支持閏月
- 返回結(jié)構(gòu)友好
- 易于擴(kuò)展
非常適合用于實(shí)際生產(chǎn)項(xiàng)目。
到此這篇關(guān)于基于Python+Flask實(shí)現(xiàn)農(nóng)歷轉(zhuǎn)換API實(shí)戰(zhàn)指南的文章就介紹到這了,更多相關(guān)Python農(nóng)歷轉(zhuǎn)換API內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python腳本設(shè)置系統(tǒng)時(shí)間的兩種方法
這篇文章主要介紹了python腳本設(shè)置系統(tǒng)時(shí)間的兩種方法,其一是調(diào)用socket直接發(fā)送udp包到國家授時(shí)中心,其二是調(diào)用ntplib包,感興趣的小伙伴們可以參考一下2016-02-02
Python實(shí)現(xiàn)圖片格式轉(zhuǎn)換
經(jīng)常會(huì)遇到圖片格式需要轉(zhuǎn)換的情況,這篇文章主要為大家詳細(xì)介紹了Python實(shí)現(xiàn)圖片格式轉(zhuǎn)換,文中示例代碼介紹的非常詳細(xì)、實(shí)用,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08
Python中使用正則表達(dá)式精準(zhǔn)匹配IP地址的案例
Python的正則表達(dá)式(re模塊)是完成這個(gè)任務(wù)的利器,但你知道怎么寫才能準(zhǔn)確匹配各種合法的IP地址嗎,今天我們就來詳細(xì)探討這個(gè)問題,感興趣的朋友一起看看吧2025-04-04
Python 帶星號(* 或 **)的函數(shù)參數(shù)詳解
這篇文章主要介紹了Python 帶星號(* 或 **)的函數(shù)參數(shù)詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02
tensorflow實(shí)現(xiàn)在函數(shù)中用tf.Print輸出中間值
今天小編就為大家分享一篇tensorflow實(shí)現(xiàn)在函數(shù)中用tf.Print輸出中間值,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-01-01
pandas 使用merge實(shí)現(xiàn)百倍加速的操作
這篇文章主要介紹了pandas 使用merge實(shí)現(xiàn)百倍加速的操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-04-04
Python使用email?庫創(chuàng)建和解析電子郵件詳解
在現(xiàn)代軟件開發(fā)中,處理電子郵件是一項(xiàng)常見的任務(wù),本文將介紹如何使用Python的??email??庫來創(chuàng)建和解析電子郵件,有需要的小伙伴可以參考一下2025-09-09

