怎样实现农历公历转换脚本

wen 实用脚本 26

本文目录导读:

怎样实现农历公历转换脚本

  1. 方案一:使用 lunardate 库(Python)
  2. 方案二:自实现算法(纯 Python)
  3. 方案三:使用 chinese-calendar 库(推荐)
  4. 方案四:JavaScript 版本
  5. 安装和使用建议

我来为你提供几种不同方式的农历公历转换脚本实现方案。

使用 lunardate 库(Python)

这是最简单的方法,使用 lunardate 库:

import lunardate
# 公历转农历
def solar_to_lunar(year, month, day):
    try:
        lunar = lunardate.LunarDate.fromSolarDate(year, month, day)
        return (lunar.year, lunar.month, lunar.day, lunar.isLeapMonth)
    except Exception as e:
        return f"转换失败: {e}"
# 农历转公历
def lunar_to_solar(lunar_year, lunar_month, lunar_day, is_leap=False):
    try:
        solar = lunardate.LunarDate(lunar_year, lunar_month, lunar_day, is_leap).toSolarDate()
        return (solar.year, solar.month, solar.day)
    except Exception as e:
        return f"转换失败: {e}"
# 使用示例
if __name__ == "__main__":
    # 公历 2024-01-01 转农历
    print(solar_to_lunar(2024, 1, 1))  # 输出: (2023, 11, 20, False) 即农历2023年冬月二十
    # 农历 2024-01-01 转公历
    print(lunar_to_solar(2024, 1, 1))  # 输出: (2024, 2, 10) 即公历2024年2月10日(春节)

自实现算法(纯 Python)

这是一个简单但功能完整的实现:

# 农历数据表(1900-2100年,每个月大小月和闰月信息)
# 每4个字节表示一年:12位表示每月大小月,4位表示闰月编号,4位表示闰月大小月
lunar_info = [
    0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2,  # 1900-1909
    0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977,  # 1910-1919
    0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970,  # 1920-1929
    0x06566, 0x0d4a0, 0x0ea50, 0x06a95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950,  # 1930-1939
    0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557,  # 1940-1949
    0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5b0, 0x14573, 0x052b0, 0x0a9a8, 0x0e950, 0x06aa0,  # 1950-1959
    0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0,  # 1960-1969
    0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b6a0, 0x195a6,  # 1970-1979
    0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570,  # 1980-1989
    0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x05ac0, 0x0ab60, 0x096d5, 0x092e0,  # 1990-1999
    0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5,  # 2000-2009
    0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930,  # 2010-2019
    0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530,  # 2020-2029
    0x05aa0, 0x076a3, 0x096d0, 0x04afb, 0x04ad0, 0x0a4d0, 0x0d0b6, 0x0d250, 0x0d520, 0x0dd45,  # 2030-2039
    0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0,  # 2040-2049
]
# 天干地支
TIAN_GAN = ['甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸']
DI_ZHI = ['子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥']
SHENG_XIAO = ['鼠', '牛', '虎', '兔', '龙', '蛇', '马', '羊', '猴', '鸡', '狗', '猪']
LUNAR_MONTH = ['正', '二', '三', '四', '五', '六', '七', '八', '九', '十', '冬', '腊']
LUNAR_DAY = ['初一', '初二', '初三', '初四', '初五', '初六', '初七', '初八', '初九', '初十',
              '十一', '十二', '十三', '十四', '十五', '十六', '十七', '十八', '十九', '二十',
              '廿一', '廿二', '廿三', '廿四', '廿五', '廿六', '廿七', '廿八', '廿九', '三十']
class LunarCalendar:
    def __init__(self):
        self.lunar_info = lunar_info
    def _get_lunar_month_days(self, lunar_year, lunar_month):
        """获取农历某月天数"""
        leap_month = self._get_leap_month(lunar_year)
        if leap_month == lunar_month:
            return 30 if self._get_leap_month_days(lunar_year) else 29
        info = self.lunar_info[lunar_year - 1900]
        return 30 if (info & (0x10000 >> lunar_month)) else 29
    def _get_leap_month(self, lunar_year):
        """获取农历年闰月"""
        return self.lunar_info[lunar_year - 1900] >> 16 & 0xf
    def _get_leap_month_days(self, lunar_year):
        """获取农历年闰月天数"""
        return self.lunar_info[lunar_year - 1900] & 0x10000
    def solar_to_lunar(self, year, month, day):
        """公历转农历"""
        # 计算输入日期距离 1900-01-31 的天数
        base_date = [1900, 1, 31]
        offset = self._day_from_1900(year, month, day) - self._day_from_1900(*base_date)
        if offset < 0:
            return None
        # 计算农历年份
        lunar_year = 1900
        while offset > 0:
            days = self._get_lunar_year_days(lunar_year)
            offset -= days
            if offset >= 0:
                lunar_year += 1
        if offset < 0:
            offset += days
            lunar_year -= 1
        # 计算农历月份
        lunar_month = 1
        leap_month = self._get_leap_month(lunar_year)
        is_leap = False
        while offset > 0:
            if lunar_month == leap_month and not is_leap:
                days = 30 if self._get_leap_month_days(lunar_year) else 29
                if offset >= days:
                    offset -= days
                    if offset == 0:
                        is_leap = True
                else:
                    break
                lunar_month += 1
            else:
                days = self._get_lunar_month_days(lunar_year, lunar_month)
                if offset >= days:
                    offset -= days
                    lunar_month += 1
                else:
                    break
        # 计算农历日期
        lunar_day = offset + 1
        return (lunar_year, lunar_month, lunar_day, is_leap)
    def lunar_to_solar(self, lunar_year, lunar_month, lunar_day, is_leap=False):
        """农历转公历"""
        # 计算该年农历天数
        days = 0
        # 计算到目标月份之前的天数
        leap_month = self._get_leap_month(lunar_year)
        for month in range(1, lunar_month):
            if month == leap_month and not is_leap:
                days += 30 if self._get_leap_month_days(lunar_year) else 29
            else:
                days += self._get_lunar_month_days(lunar_year, month)
        # 处理闰月
        if is_leap and lunar_month == leap_month:
            days += 30 if self._get_leap_month_days(lunar_year) else 29
        # 加上当前月的天数
        if is_leap and lunar_month == leap_month:
            days += lunar_day
        else:
            days += lunar_day
        # 从1900-01-31算起
        base_date = [1900, 1, 31]
        offset = days
        # 计算公历日期
        return self._date_from_1900(self._day_from_1900(*base_date) + offset)
    def _get_lunar_year_days(self, year):
        """获取农历年总天数"""
        # 这里简化计算,实际需要根据农历数据表计算
        info = self.lunar_info[year - 1900]
        total = 0
        for month in range(1, 13):
            total += 30 if (info & (0x10000 >> month)) else 29
        leap_month = info >> 16 & 0xf
        if leap_month:
            total += 30 if info & 0x10000 else 29
        return total
    def _day_from_1900(self, year, month, day):
        """计算从1900年1月0日开始的天数"""
        days = 0
        for y in range(1900, year):
            days += 366 if self._is_leap_year(y) else 365
        for m in range(1, month):
            days += self._get_month_days(year, m)
        return days + day
    def _date_from_1900(self, days):
        """从1900年1月0日开始计算公历日期"""
        year = 1900
        while days > 0:
            year_days = 366 if self._is_leap_year(year) else 365
            if days <= year_days:
                break
            days -= year_days
            year += 1
        month_days = [31, 29 if self._is_leap_year(year) else 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
        month = 1
        for m in range(12):
            if days <= month_days[m]:
                month = m + 1
                break
            days -= month_days[m]
        return (year, month, days)
    def _is_leap_year(self, year):
        """判断是否为闰年"""
        return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
    def _get_month_days(self, year, month):
        """获取公历月份天数"""
        if month in [1, 3, 5, 7, 8, 10, 12]:
            return 31
        elif month in [4, 6, 9, 11]:
            return 30
        else:
            return 29 if self._is_leap_year(year) else 28
# 使用示例
if __name__ == "__main__":
    calendar = LunarCalendar()
    # 公历 2024-01-01 转农历
    print(calendar.solar_to_lunar(2024, 1, 1))  
    # 农历 2024-01-01 转公历
    print(calendar.lunar_to_solar(2024, 1, 1))

使用 chinese-calendar 库(推荐)

这个库更专业,功能更丰富:

pip install chinese-calendar
from chinese_calendar import lunar_to_solar, solar_to_lunar
from datetime import date
# 公历转农历
def solar_to_lunar_demo():
    dt = date(2024, 1, 1)
    lunar_date = solar_to_lunar(dt)
    print(f"公历 2024-01-01 对应农历: {lunar_date.year}-{lunar_date.month}-{lunar_date.day}")
    print(f"是否闰月: {lunar_date.is_leap_month}")
# 农历转公历
def lunar_to_solar_demo():
    lunar_date = lunar_to_solar(2024, 1, 1)
    print(f"农历 2024-01-01 对应公历: {lunar_date.year}-{lunar_date.month}-{lunar_date.day}")
if __name__ == "__main__":
    solar_to_lunar_demo()
    lunar_to_solar_demo()

JavaScript 版本

// lunarcalendar.js
class LunarCalendar {
    constructor() {
        // 农历数据表(同上)
        this.lunarInfo = [
            0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2,
            // ... 完整数据需从Python版本复制
        ];
        this.TIAN_GAN = ['甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸'];
        this.DI_ZHI = ['子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥'];
        // ... 其他常量
    }
    solarToLunar(year, month, day) {
        // 实现逻辑与Python版本相同
        // 这里简化处理,实际需要完整实现
        const baseDate = new Date(1900, 0, 31); // JS中月份从0开始
        const targetDate = new Date(year, month - 1, day);
        const offset = Math.floor((targetDate - baseDate) / (24 * 60 * 60 * 1000));
        // 根据偏移量计算农历日期
        // 需要完整实现
        return { year: 0, month: 0, day: 0, isLeap: false };
    }
    lunarToSolar(lunarYear, lunarMonth, lunarDay, isLeap = false) {
        // 实现逻辑与Python版本相同
        // 需要完整实现
        return { year: 0, month: 0, day: 0 };
    }
}
// 使用示例
const calendar = new LunarCalendar();
console.log(calendar.solarToLunar(2024, 1, 1));

安装和使用建议

  1. 推荐使用 chinese-calendar(如果只需要基本功能)

  2. 如果需要完整功能,使用 lunardate

  3. 如果不想依赖外部库,使用自实现算法

  4. 注意闰月处理:实现时要特别注意闰月的判断

这些实现应该能满足大部分农历公历转换的需求,如果还有具体问题,欢迎继续询问!

抱歉,评论功能暂时关闭!