乐水悠悠

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 :: 管理 ::

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()
posted on 2025-12-01 14:07  金币闪耀  阅读(0)  评论(0)    收藏  举报