Python有一些公历转农历的库,但是转出来的年份都是二零二四、二零二五这样的数字,我希望转成甲子、丙申这种天干地支形式,正好发现万象拼音的shijian.lua脚本里面有类似的功能,参照它实现了python版本的公历转农历,这里把代码记录下:
import math
from datetime import datetime, timedelta
# 农历数据表(1900-2100年)
wNongliData = [
"AB500D2", "4BD0883", "4AE00DB", "A5700D0", "54D0581", "D2600D8", "D9500CC", "655147D", "56A00D5", "9AD00CA",
"55D027A", "4AE00D2", "A5B0682", "A4D00DA", "D2500CE", "D25157E", "B5400D6", "D6A00CB", "ADA027B", "95B00D3",
"49717C9", "49700DC", "A4B00D0", "B4B0580", "6A500D8", "6D400CD", "AB5147C", "2B600D5", "95700CA", "52F027B",
"49700D2", "6560682", "D4A00D9", "EA500CE", "6A9157E", "5AD00D6", "2B600CC", "86E137C", "92E00D3", "C8D1783",
"C9500DB", "D4A00D0", "D8A167F", "B5500D7", "56A00CD", "A5B147D", "25D00D5", "92D00CA", "D2B027A", "A9500D2",
"B550781", "6CA00D9", "B5500CE", "535157F", "4DA00D6", "A5B00CB", "457137C", "52B00D4", "A9A0883", "E9500DA",
"6AA00D0", "AEA0680", "AB500D7", "4B600CD", "AAE047D", "A5700D5", "52600CA", "F260379", "D9500D1", "5B50782",
"56A00D9", "96D00CE", "4DD057F", "4AD00D7", "A4D00CB", "D4D047B", "D2500D3", "D550883", "B5400DA", "B6A00CF",
"95A1680", "95B00D8", "49B00CD", "A97047D", "A4B00D5", "B270ACA", "6A500DC", "6D400D1", "AF40681", "AB600D9",
"95700CE", "4AF057F", "49700D7", "64B00CC", "74A037B", "EA500D2", "6B50883", "5AC00DB", "AB600CF", "96D0580",
"92E00D8", "C9600CD", "D95047C", "D4A00D4", "DA500C9", "755027A", "56A00D1", "ABB0781", "25D00DA", "92D00CF",
"CAB057E", "A9500D6", "B4A00CB", "BAA047B", "AD500D2", "55D0983", "4BA00DB", "A5B00D0", "5171680", "52B00D8",
"A9300CD", "795047D", "6AA00D4", "AD500C9", "5B5027A", "4B600D2", "A6E0681", "A4E00D9", "D2600CE", "EA6057E",
"D5300D5", "5AA00CB", "76A037B", "96D00D3", "4AF0B83", "4AD00DB", "A4D00D0", "D0B1680", "D2500D7", "D5200CC",
"DD4057C", "B5A00D4", "56D00C9", "55B027A", "49B00D2", "A570782", "A4B00D9", "AA500CE", "B25157E", "6D200D6",
"ADA00CA", "4B6137B", "93700D3", "49F08C9", "49700DB", "64B00D0", "68A1680", "EA500D7", "6AA00CC", "A6C147C",
"AAE00D4", "92E00CA", "D2E0379", "C9600D1", "D550781", "D4A00D9", "DA500CD", "5D5057E", "56A00D6", "A6D00CB",
"55D047B", "52D00D3", "A9B0883", "A9500DB", "B4A00CF", "B6A067F", "AD500D7", "55A00CD", "ABA047C", "A5B00D4",
"52B00CA", "B27037A", "69300D1", "7330781", "6AA00D9", "AD500CE", "4B5157E", "4B600D6", "A5700CB", "54E047C",
"D1600D2", "E960882", "D5200DA", "DAA00CF", "6AA167F", "56D00D7", "4AE00CD", "A9D047D", "A2D00D4", "D1500C9",
"F250279", "D5200D1", "DB20781", "B5A00D9", "55D00CF", "4DB0580", "49B00D7", "A4B00CC", "D4B047C", "AA500D4",
"B550983", "6D200DB", "AD600D0", "5760681", "93700D8"
]
# 天干名称
cTianGan = ["甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"]
# 地支名称
cDiZhi = ["子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"]
# 属相名称
cShuXiang = ["鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊", "猴", "鸡", "狗", "猪"]
# 农历日期名
cDayName = [
"初一", "初二", "初三", "初四", "初五", "初六", "初七", "初八", "初九", "初十",
"十一", "十二", "十三", "十四", "十五", "十六", "十七", "十八", "十九", "二十",
"廿一", "廿二", "廿三", "廿四", "廿五", "廿六", "廿七", "廿八", "廿九", "三十"
]
# 农历月份名
cMonName = ["正月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "冬月", "腊月"]
def Analyze(Data):
"""农历16进制数据分解"""
# 前3位转二进制
rtn1 = bin(int(Data[0:3], 16))[2:].zfill(12)
rtn2 = Data[3:4] # 第4位
# 第5位转十进制
rtn3 = int(Data[4:5], 16)
# 最后2位转十进制
rtn4 = int(Data[5:7], 16)
if len(str(rtn4)) == 3:
rtn4 = "0" + str(rtn4)
# 月份信息(0:本月29天,1:本月30天),闰月信息(多出来的闰月是29还是30天),闰月(闰月月份),春节日期(MMDD形式)
return [rtn1, rtn2, rtn3, rtn4]
def IsLeap(year):
"""判断是否为闰年"""
if (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0):
return 366
else:
return 365
def leaveDate(date_str):
"""返回当年过了多少天"""
y = int(date_str[:4])
m = int(date_str[4:6])
d = int(date_str[6:8])
if IsLeap(y) == 366:
days_in_month = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
else:
days_in_month = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
total = 0
if m > 1:
for i in range(0, m-1):
total += days_in_month[i]
total += d
return total
def diffDate(date1, date2):
"""计算两个日期的相差天数,date2 > date1"""
if len(date1) != 8 or len(date2) != 8:
return -1
y1, m1, d1 = int(date1[:4]), int(date1[4:6]), int(date1[6:8])
y2, m2, d2 = int(date2[:4]), int(date2[4:6]), int(date2[6:8])
if y1 == y2 and m1 == m2 and d1 == d2:
return 0
if y1 > y2 or (y1 == y2 and (m1 > m2 or (m1 == m2 and d1 > d2))):
return -1
total = 0
# 相差年份
n = y2 - y1
if n > 1:
for i in range(1, n):
total += IsLeap(y1 + i)
total += leaveDate(date2) + IsLeap(y1) - leaveDate(date1)
elif n == 1:
total = IsLeap(y1) - leaveDate(date1) + leaveDate(date2)
else:
total = leaveDate(date2) - leaveDate(date1)
return total
def Date2LunarDate(Gregorian):
"""公历转农历,支持1900-2100年"""
if len(str(Gregorian)) < 8:
return "无效日期"
Gregorian = str(Gregorian)
Year = int(Gregorian[:4])
Month = int(Gregorian[4:6])
Day = int(Gregorian[6:8])
# 检查日期有效性
if Year > 2100 or Year < 1900 or Month > 12 or Month < 1 or Day < 1 or Day > 31:
return "无效日期"
# 获取两百年内的农历数据
Pos = Year - 1900 + 2
if Pos - 2 < 0 or Pos - 2 >= len(wNongliData):
return "年份超出范围"
Data0 = wNongliData[Pos - 2] # 上一年数据
Data1 = wNongliData[Pos - 1] # 本年数据
# 判断农历年份
tb1 = Analyze(Data1)
MonthInfo = tb1[0] # 月份信息
LeapInfo = tb1[1] # 闰月信息
Leap = tb1[2] # 闰月
Newyear = tb1[3] # 春节日期
Date1 = str(Year) + str(Newyear).zfill(4)
Date2 = Gregorian
Date3 = diffDate(Date1, Date2) # 和当年农历新年相差的天数
if Date3 < 0: # 如果在春节之前,使用上一年数据
tb1 = Analyze(Data0)
Year = Year - 1
MonthInfo = tb1[0]
LeapInfo = tb1[1]
Leap = tb1[2]
Newyear = tb1[3]
Date1 = str(Year) + str(Newyear).zfill(4)
Date2 = Gregorian
Date3 = diffDate(Date1, Date2)
Date3 = Date3 + 1
LYear = Year # 农历年份
# 处理闰月信息
if Leap > 0: # 有闰月
Leap = int(Leap)
thisMonthInfo = MonthInfo[:Leap] + LeapInfo + MonthInfo[Leap:]
else:
thisMonthInfo = MonthInfo
LMonth = 0
LDay = 0
Isleap = 0
# 计算农历月日
for i in range(len(thisMonthInfo)):
thisMonth = thisMonthInfo[i]
thisDays = 29 + int(thisMonth)
if Date3 > thisDays:
Date3 = Date3 - thisDays
else:
if Leap > 0:
if i >= Leap:
LMonth = i
Isleap = 0
else:
LMonth = i + 1
if i + 1 - Leap == 1:
Isleap = 1
else:
Isleap = 0
else:
LMonth = i + 1
Isleap = 0
LDay = Date3
break
# 处理月份显示
if Isleap > 0:
LunarMonth = "闰" + cMonName[LMonth - 1]
else:
LunarMonth = cMonName[LMonth - 1]
# 计算天干地支
TianGanIndex = (LYear - 4) % 10
DiZhiIndex = (LYear - 4) % 12
ShuXiangIndex = (LYear - 4) % 12
LunarYear = (cTianGan[TianGanIndex] + cDiZhi[DiZhiIndex] + "年(" +
cShuXiang[ShuXiangIndex] + ")" + LunarMonth + cDayName[LDay - 1])
return LunarYear
# 测试函数
def test_lunar_conversion():
"""测试公历转农历功能"""
test_dates = [
"20240101", # 2024年元旦
"20240205", # 2024年元宵节附近
"20240929", # 2024年中秋节附近
"20241001", # 2024年国庆节
"20250101", # 2025年元旦
]
print("公历转农历测试:")
print("-" * 50)
for date in test_dates:
lunar = Date2LunarDate(date)
print(f"公历 {date[:4]}年{date[4:6]}月{date[6:8]}日 → 农历 {lunar}")
if __name__ == "__main__":
# 测试当前日期
today = datetime.now().strftime("%Y%m%d")
lunar_today = Date2LunarDate(today)
print(f"今日公历: {today[:4]}年{today[4:6]}月{today[6:8]}日")
print(f"今日农历: {lunar_today}")
print()
# 运行测试
test_lunar_conversion()

浙公网安备 33010602011771号