当前位置: 首页 > news >正文

Python实现公历转农历

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 366else:return 365def 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 = 0if m > 1:for i in range(0, m-1):total += days_in_month[i]total += dreturn totaldef diffDate(date1, date2):"""计算两个日期的相差天数,date2 > date1"""if len(date1) != 8 or len(date2) != 8:return -1y1, 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 0if y1 > y2 or (y1 == y2 and (m1 > m2 or (m1 == m2 and d1 > d2))):return -1total = 0# 相差年份n = y2 - y1if 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 totaldef 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 + 2if 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 = GregorianDate3 = diffDate(Date1, Date2)  # 和当年农历新年相差的天数if Date3 < 0:  # 如果在春节之前,使用上一年数据tb1 = Analyze(Data0)Year = Year - 1MonthInfo = tb1[0]LeapInfo = tb1[1]Leap = tb1[2]Newyear = tb1[3]Date1 = str(Year) + str(Newyear).zfill(4)Date2 = GregorianDate3 = diffDate(Date1, Date2)Date3 = Date3 + 1LYear = Year  # 农历年份# 处理闰月信息if Leap > 0:  # 有闰月Leap = int(Leap)thisMonthInfo = MonthInfo[:Leap] + LeapInfo + MonthInfo[Leap:]else:thisMonthInfo = MonthInfoLMonth = 0LDay = 0Isleap = 0# 计算农历月日for i in range(len(thisMonthInfo)):thisMonth = thisMonthInfo[i]thisDays = 29 + int(thisMonth)if Date3 > thisDays:Date3 = Date3 - thisDayselse:if Leap > 0:if i >= Leap:LMonth = iIsleap = 0else:LMonth = i + 1if i + 1 - Leap == 1:Isleap = 1else:Isleap = 0else:LMonth = i + 1Isleap = 0LDay = Date3break# 处理月份显示if Isleap > 0:LunarMonth = "闰" + cMonName[LMonth - 1]else:LunarMonth = cMonName[LMonth - 1]# 计算天干地支TianGanIndex = (LYear - 4) % 10DiZhiIndex = (LYear - 4) % 12ShuXiangIndex = (LYear - 4) % 12LunarYear = (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()