Lunar Calendar Converter 農曆轉換工具

一套使用 Python 3.13+ 與 Skyfield 天文資料庫實作的農曆轉換工具，支援西曆↔農曆、閏月查詢，並提供 CLI 與 API（FastAPI）。

需求

- Python >= 3.13（可用 uv 安裝）
- 套件：
  - skyfield
  - jplephem
  - numpy
  - fastapi、uvicorn（僅在使用 API 時）
- Skyfield 天文資料檔（本庫已附）：
  - de422.bsp（程式目前預設使用）
  - de440s.bsp、de421.bsp（可替代）

安裝與環境（使用 uv）

初始化與安裝依賴（如已存在可略過 init）
uv init lunar-converter
cd lunar-converter
uv add skyfield jplephem numpy flask
uv lock
uv sync

uv 會自動建立 .venv/ 虛擬環境，無需手動啟動。

專案結構（重點檔案）

.
├── converter.py                  # 西曆↔農曆轉換核心與閏月查詢（供程式/API 使用）
├── converter_with_eras.py        # 指令列工具：solar2lunar / lunar2solar / era
├── api.py                        # FastAPI 服務
├── generate_lunar_calendar_json.py # 批次產生 JSON（可自訂年份範圍）
├── lunar_calendar.py             # 天文計算與 JSON 產生
├── lunar_json/                   # 每年一檔的農曆 JSON（執行產生器後）

產生農曆資料（JSON）

預設腳本為 `generate_lunar_calendar_json.py`，內含可調整的年份範圍。

uv run python generate_lunar_calendar_json.py

會輸出到 `lunar_json/`，例如：`lunar_json/2025.json`。

若只想產生 1900–2100，可修改腳本內的 years 範圍：

# generate_lunar_calendar_json.py
# years = range(1900, 2101)

指令列（CLI）使用

CLI 功能位於 `converter_with_eras.py`：

uv run python converter_with_eras.py solar2lunar 2025-10-12
uv run python converter_with_eras.py lunar2solar 1977-08-30 --leap   # 閏月請加上 --leap
uv run python converter_with_eras.py era 1906-02-07                  # 歷代年號 / 日本元號查詢

範例輸出（solar2lunar）

{
  "西曆": "2025-10-12",
  "農曆": "8月21日",
  "干支": "乙巳",
  "生肖": "蛇",
  "節氣": ""
}

啟用 API（FastAPI）

uv run python api.py

程式會自動尋找可用埠（預設從 5000 開始）。可瀏覽 `/docs` 或 `/redoc` 查看互動式文件。
或直接用 Uvicorn 啟動：

uv run uvicorn api:app --host 0.0.0.0 --port 5000

API 範例

# 查詢一個存在的日期
curl "http://127.0.0.1:5001/solar2lunar?date=2025-10-06" | jq

# 不提供 date 參數
curl "http://127.0.0.1:5001/solar2lunar" | jq

# 查詢一個沒有閏月的日期
curl "http://127.0.0.1:5001/lunar2solar?date=1977-08-30" | jq

# 查詢一個有閏月的日期
curl "http://127.0.0.1:5001/lunar2solar?date=1976-08-25" | jq

# 查詢一個不存在的日期（會得到 404）
curl -i "http://127.0.0.1:5001/lunar2solar?date=2025-08-30"

# 查詢 2023 年（該年有閏二月）
curl "http://127.0.0.1:5001/leap-info?year=2023" | jq

# 查詢 1977 年
curl "http://127.0.0.1:5001/leap-info?year=1977" | jq

# 提供一個非數字的年份
curl "http://127.0.0.1:5001/leap-info?year=abc" | jq

備註

- 干支與生肖依據「農曆年」切換。
- 使用 Skyfield 計算節氣與朔望月，精度高於傳統對照表。
- 目前 `lunar_calendar.py` 預設載入 `de422.bsp`。欲改用 `de440s.bsp` 或 `de421.bsp`，請修改：
  self.eph = load('de422.bsp')
- 若缺少某年 JSON 檔，查詢會提示錯誤，請先執行產生器產生對應年份。

作者

由 Timmy（羅楊竣）開發。

MIT License

開發小工具（直接使用 uv 指令）

- `uv run --group dev black .`：使用 Black 格式化專案
- `uv run --group dev ruff format .`：使用 Ruff 內建 formatter 格式化
- `uv run --group dev ruff check .`：Ruff 檢查
- `uv run --group dev ruff check --fix .`：Ruff 自動修正
