python3实现万年历(包括公历、农历、节气、节日)

转载:https://www.cnblogs.com/lanzhi/p/6468355.html

#!/usr/local/bin/python3
# coding=utf-8
# Created:     20/07/2012
# Copyright:   http://www.cnblogs.com/txw1958/
'''
A Chinese Calendar Library in Python
'''


import os, io, sys, re, time, datetime, base64

__version__ = "$Rev: 123 $"
__all__ = ['LunarDate']


solar_year          = 1900
solar_month         = 1
solar_day           = 31
solar_weekday          = 0

lunar_year          = 0
lunar_month         = 0
lunar_day           = 0
lunar_isLeapMonth   = False


class LunarDate(object):
    _startDate = datetime.date(1900, 1, 31)

    def __init__(self, year, month, day, isLeapMonth=False):
        global lunar_year
        global lunar_month
        global lunar_day
        global lunar_isLeapMonth

        lunar_year          = int(year)
        lunar_month         = int(month)
        lunar_day           = int(day)
        lunar_isLeapMonth   = bool(isLeapMonth)

        self.year = year
        self.month = month
        self.day = day
        self.isLeapMonth = bool(isLeapMonth)

    def __str__(self):
        return 'LunarDate(%d, %d, %d, %d)' % (self.year, self.month, self.day, self.isLeapMonth)

    __repr__ = __str__

    @staticmethod
    def fromSolarDate(year, month, day):
        solarDate = datetime.date(year, month, day)
        offset = (solarDate - LunarDate._startDate).days
        return LunarDate._fromOffset(offset)

    def toSolarDate(self):
        def _calcDays(yearInfo, month, day, isLeapMonth):
            isLeapMonth = int(isLeapMonth)
            res = 0
            ok = False
            for _month, _days, _isLeapMonth in self._enumMonth(yearInfo):
                if (_month, _isLeapMonth) == (month, isLeapMonth):
                    if 1 <= day <= _days:
                        res += day - 1
                        return res
                    else:
                        raise ValueError("day out of range")
                res += _days

            raise ValueError("month out of range")

        offset = 0
        if self.year < 1900 or self.year >= 2050:
            raise ValueError('year out of range [1900, 2050)')
        yearIdx = self.year - 1900
        for i in range(yearIdx):
            offset += yearDays[i]

        offset += _calcDays(yearInfos[yearIdx], self.month, self.day, self.isLeapMonth)
        return self._startDate + datetime.timedelta(days=offset)

    def __sub__(self, other):
        if isinstance(other, LunarDate):
            return self.toSolarDate() - other.toSolarDate()
        elif isinstance(other, datetime.date):
            return self.toSolarDate() - other
        elif isinstance(other, datetime.timedelta):
            res = self.toSolarDate() - other
            return LunarDate.fromSolarDate(res.year, res.month, res.day)
        raise TypeError

    def __rsub__(self, other):
        if isinstance(other, datetime.date):
            return other - self.toSolarDate()

    def __add__(self, other):
        if isinstance(other, datetime.timedelta):
            res = self.toSolarDate() + other
            return LunarDate.fromSolarDate(res.year, res.month, res.day)
        raise TypeError

    def __radd__(self, other):
        return self + other

    def __lt__(self, other):
        return self - other < datetime.timedelta(0)

    def __le__(self, other):
        return self - other <= datetime.timedelta(0)

    @classmethod
    def today(cls):
        res = datetime.date.today()
        return cls.fromSolarDate(res.year, res.month, res.day)

    @staticmethod
    def _enumMonth(yearInfo):
        months = [(i, 0) for i in range(1, 13)]
        leapMonth = yearInfo % 16
        if leapMonth == 0:
            pass
        elif leapMonth <= 12:
            months.insert(leapMonth, (leapMonth, 1))
        else:
            raise ValueError("yearInfo %r mod 16 should in [0, 12]" % yearInfo)

        for month, isLeapMonth in months:
            if isLeapMonth:
                days = (yearInfo >> 16) % 2 + 29
            else:
                days = (yearInfo >> (16 - month)) % 2 + 29
            yield month, days, isLeapMonth

    @classmethod
    def _fromOffset(cls, offset):
        def _calcMonthDay(yearInfo, offset):
            for month, days, isLeapMonth in cls._enumMonth(yearInfo):
                if offset < days:
                    break
                offset -= days
            return (month, offset + 1, isLeapMonth)

        offset = int(offset)

        for idx, yearDay in enumerate(Info.yearDays()):
            if offset < yearDay:
                break
            offset -= yearDay
        year = 1900 + idx

        yearInfo = Info.yearInfos[idx]
        month, day, isLeapMonth = _calcMonthDay(yearInfo, offset)
        return LunarDate(year, month, day, isLeapMonth)

class ChineseWord():
    def weekday_str(tm):
        a = '星期日 星期一 星期二 星期三 星期四 星期五 星期六'.split()
        return a[tm]

    def solarTerm(year, month, day):
        a = '小寒 大寒 立春 雨水 惊蛰 春分\
             清明 谷雨 立夏 小满 芒种 夏至\
             小暑 大暑 立秋 处暑 白露 秋分\
             寒露 霜降 立冬 小雪 大雪 冬至'.split()
        return

    def day_lunar(ld):
        a = '初一 初二 初三 初四 初五 初六 初七 初八 初九 初十\
             十一 十二 十三 十四 十五 十六 十七 十八 十九 廿十\
             廿一 廿二 廿三 廿四 廿五 廿六 廿七 廿八 廿九 三十'.split()
        return a[ld - 1]

    def month_lunar(le, lm):
        a = '正月 二月 三月 四月 五月 六月 七月 八月 九月 十月 十一月 十二月'.split()
        if le:
            return "闰" + a[lm - 1]
        else:
            return a[lm - 1]

    def year_lunar(ly):
        y = ly
        tg = '甲 乙 丙 丁 戊 己 庚 辛 壬 癸'.split()
        dz = '子 丑 寅 卯 辰 巳 午 未 申 酉 戌 亥'.split()
        sx = '鼠 牛 虎 兔 龙 蛇 马 羊 猴 鸡 狗 猪'.split()
        return tg[(y - 4) % 10] + dz[(y - 4) % 12] + '[' + sx[(y - 4) % 12] + ']' + '年'

class Festival():
    #国历节日 *表示放假日
    def solar_Fstv(solar_month, solar_day):
        sFtv = [
        "0101#元旦节#",
        "0202#世界湿地日#",
        "0210#国际气象节#",
        "0214#情人节#",
        "0301#国际海豹日#",
        "0303#全国爱耳日#",
        "0305#学雷锋纪念日#",
        "0308#妇女节#",
        "0312#植树节# #孙中山逝世纪念日#",
        "0314#国际警察日#",
        "0315#消费者权益日#",
        "0317#中国国医节# #国际航海日#",
        "0321#世界森林日# #消除种族歧视国际日# #世界儿歌日#",
        "0322#世界水日#",
        "0323#世界气象日#",
        "0324#世界防治结核病日#",
        "0325#全国中小学生安全教育日#",
        "0330#巴勒斯坦国土日#",
        "0401#愚人节# #全国爱国卫生运动月(四月)# #税收宣传月(四月)#",
        "0407#世界卫生日#",
        "0422#世界地球日#",
        "0423#世界图书和版权日#",
        "0424#亚非新闻工作者日#",
        "0501#劳动节#",
        "0504#青年节#",
        "0505#碘缺乏病防治日#",
        "0508#世界红十字日#",
        "0512#国际护士节#",
        "0515#国际家庭日#",
        "0517#国际电信日#",
        "0518#国际博物馆日#",
        "0520#全国学生营养日#",
        "0523#国际牛奶日#",
        "0531#世界无烟日#",
        "0601#国际儿童节#",
        "0605#世界环境保护日#",
        "0606#全国爱眼日#",
        "0617#防治荒漠化和干旱日#",
        "0623#国际奥林匹克日#",
        "0625#全国土地日#",
        "0626#国际禁毒日#",
        "0701#中国共·产党诞辰# #香港回归纪念日# #世界建筑日#",
        "0702#国际体育记者日#",
        "0707#抗日战争纪念日#",
        "0711#世界人口日#",
        "0730#非洲妇女日#",
        "0801#建军节#",
        "0808#中国男子节(爸爸节)#",
        "0815#抗日战争胜利纪念#",
        "0908#国际扫盲日# #国际新闻工作者日#",
        "0909#毛·泽东逝世纪念#",
        "0910#中国教师节#",
        "0914#世界清洁地球日#",
        "0916#国际臭氧层保护日#",
        "0918#九·一八事变纪念日#",
        "0920#国际爱牙日#",
        "0927#世界旅游日#",
        "0928#孔子诞辰#",
        "1001#国庆节# #世界音乐日# #国际老人节#",
        "1002#国庆节假日# #国际和平与民主自由斗争日#",
        "1003#国庆节假日#",
        "1004#世界动物日#",
        "1006#老人节#",
        "1008#全国高血压日# #世界视觉日#",
        "1009#世界邮政日# #万国邮联日#",
        "1010#辛亥革命纪念日# #世界精神卫生日#",
        "1013#世界保健日# #国际教师节#",
        "1014#世界标准日#",
        "1015#国际盲人节(白手杖节)#",
        "1016#世界粮食日#",
        "1017#世界消除贫困日#",
        "1022#世界传统医药日#",
        "1024#联合国日#",
        "1031#世界勤俭日#",
        "1107#十月社会主义革命纪念日#",
        "1108#中国记者日#",
        "1109#全国消防安全宣传教育日#",
        "1110#世界青年节#",
        "1111#国际科学与和平周(本日所属的一周)#",
        "1112#孙中山诞辰纪念日#",
        "1114#世界糖尿病日#",
        "1116#国际宽容日#",
        "1117#国际大学生节# #世界学生节#",
        "1120#彝族年#",
        "1121#彝族年# #世界问候日# #世界电视日#",
        "1122#彝族年#",
        "1129#国际声援巴勒斯坦人民国际日#",
        "1201#世界艾滋病日#",
        "1203#世界残疾人日#",
        "1205#国际经济和社会发展志愿人员日#",
        "1208#国际儿童电视日#",
        "1209#世界足球日#",
        "1210#世界人权日#",
        "1212#西安事变纪念日#",
        "1213#南京大屠杀(1937年)纪念日#",
        "1220#澳门回归纪念#",
        "1221#国际篮球日#",
        "1224#平安夜#",
        "1225#圣诞节#",
        "1226#毛·泽东诞辰纪念日#"
        ]
        solar_month_str = str(solar_month) if solar_month > 9 else "0" + str(solar_month)
        solar_day_str = str(solar_day) if solar_day > 9 else "0" + str(solar_day)
        pattern = "(" + solar_month_str + solar_day_str + ")([\w+?\#?\(?\)?\d+\s?·?]*)"
        for solar_fstv_item in sFtv:
            result = re.search(pattern, solar_fstv_item)
            if result is not None:
                return result.group(2)


    def lunar_Fstv(lunar_month, lunar_day):
        #农历节日 *表示放假日
        #每年单独来算
        lFtv = [
        "0101#春节#",
        "0115#元宵节#",
        "0202#春龙节",
        #"0314#清明节#", #每年不一样,此为2012年,事实上为公历节日
        "0505#端午节#",
        "0707#七夕情人节#",
        "0715#中元节#",
        "0815#中秋节#",
        "0909#重阳节#",
        "1208#腊八节#",
        "1223#小年#",
        "1229#除夕#"   #每年不一样,此为2011年
        ]
        lunar_month_str = str(lunar_month) if lunar_month > 9 else "0" + str(lunar_month)
        lunar_day_str = str(lunar_day) if lunar_day > 9 else "0" + str(lunar_day)
        pattern = "(" + lunar_month_str + lunar_day_str + ")([\w+?\#?\s?]*)"
        for lunar_fstv_item in lFtv:
            result = re.search(pattern, lunar_fstv_item)
            if result is not None:
                return result.group(2)

    #国历节日 *表示放假日
    def weekday_Fstv(solar_month, solar_day, solar_weekday):
        #某月的第几个星期几
        wFtv = [
        "0150#世界防治麻风病日#", #一月的最后一个星期日(月倒数第一个星期日)
        "0520#国际母亲节#",
        "0530#全国助残日#",
        "0630#父亲节#",
        "0730#被奴役国家周#",
        "0932#国际和平日#",
        "0940#国际聋人节# #世界儿童日#",
        "0950#世界海事日#",
        "1011#国际住房日#",
        "1013#国际减轻自然灾害日(减灾日)#",
        "1144#感恩节#"]

        #7,14等应该属于1, 2周,能整除的那天实际属于上一周,做个偏移
        offset = -1 if solar_day % 7 == 0 else 0
        #计算当前日属于第几周,得出来从0开始计周,再向后偏移1
        weekday_ordinal = solar_day // 7 + offset + 1

        solar_month_str = str(solar_month) if solar_month > 9 else "0" + str(solar_month)
        solar_weekday_str = str(weekday_ordinal) + str(solar_weekday)

        pattern = "(" + solar_month_str + solar_weekday_str + ")([\w+?\#?\s?]*)"
        for weekday_fstv_item in wFtv:
            result = re.search(pattern, weekday_fstv_item)
            if result is not None:
                return result.group(2)

        #如何计算某些最后一个星期几的情况,..........

    #24节气
    def solar_Term(solar_month, solar_day):
        #每年数据不一样,此为2012年内的数据
        stFtv = [
        "0106#小寒#",
        "0120#大寒#",
        "0204#立春#",
        "0219#雨水#",
        "0305#惊蛰#",
        "0320#春分#",
        "0404#清明#",
        "0420#谷雨#",
        "0505#立夏#",
        "0521#小满#",
        "0605#芒种#",
        "0621#夏至#",
        "0707#小暑#",
        "0722#大暑#",
        "0807#立秋#",
        "0823#处暑#",
        "0907#白露#",
        "0922#秋分#",
        "1008#寒露#",
        "1023#霜降#",
        "1107#立冬#",
        "1122#小雪#",
        "1206#大雪#",
        "1221#冬至#",
        ]
        solar_month_str = str(solar_month) if solar_month > 9 else "0" + str(solar_month)
        solar_day_str = str(solar_day) if solar_day > 9 else "0" + str(solar_day)
        pattern = "(" + solar_month_str + solar_day_str + ")([\w+?\#?]*)"
        for solarTerm_fstv_item in stFtv:
            result = re.search(pattern, solarTerm_fstv_item)
            if result is not None:
                return result.group(2)

class Info():
    yearInfos = [
        #    /* encoding:
        #               b bbbbbbbbbbbb bbbb
        #       bit#    1 111111000000 0000
        #               6 543210987654 3210
        #               . ............ ....
        #       month#    000000000111
        #               M 123456789012   L
        #
        #    b_j = 1 for long month, b_j = 0 for short month
        #    L is the leap month of the year if 1<=L<=12; NO leap month if L = 0.
        #    The leap month (if exists) is long one iff M = 1.
        #    */
        0x04bd8,                                    #   /* 1900 */
        0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950,#   /* 1905 */
        0x16554, 0x056a0, 0x09ad0, 0x055d2, 0x04ae0,#   /* 1910 */
        0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540,#   /* 1915 */
        0x0d6a0, 0x0ada2, 0x095b0, 0x14977, 0x04970,#   /* 1920 */
        0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54,#   /* 1925 */
        0x02b60, 0x09570, 0x052f2, 0x04970, 0x06566,#   /* 1930 */
        0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60,#   /* 1935 */
        0x186e3, 0x092e0, 0x1c8d7, 0x0c950, 0x0d4a0,#   /* 1940 */
        0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0,#   /* 1945 */
        0x092d0, 0x0d2b2, 0x0a950, 0x0b557, 0x06ca0,#   /* 1950 */
        0x0b550, 0x15355, 0x04da0, 0x0a5d0, 0x14573,#   /* 1955 */
        0x052d0, 0x0a9a8, 0x0e950, 0x06aa0, 0x0aea6,#   /* 1960 */
        0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260,#   /* 1965 */
        0x0f263, 0x0d950, 0x05b57, 0x056a0, 0x096d0,#   /* 1970 */
        0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250,#   /* 1975 */
        0x0d558, 0x0b540, 0x0b5a0, 0x195a6, 0x095b0,#   /* 1980 */
        0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50,#   /* 1985 */
        0x06d40, 0x0af46, 0x0ab60, 0x09570, 0x04af5,#   /* 1990 */
        0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58,#   /* 1995 */
        0x05ac0, 0x0ab60, 0x096d5, 0x092e0, 0x0c960,#   /* 2000 */
        0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0,#   /* 2005 */
        0x0abb7, 0x025d0, 0x092d0, 0x0cab5, 0x0a950,#   /* 2010 */
        0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0,#   /* 2015 */
        0x0a5b0, 0x15176, 0x052b0, 0x0a930, 0x07954,#   /* 2020 */
        0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6,#   /* 2025 */
        0x0a4e0, 0x0d260, 0x0ea65, 0x0d530, 0x05aa0,#   /* 2030 */
        0x076a3, 0x096d0, 0x04afb, 0x04ad0, 0x0a4d0,#   /* 2035 */
        0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, 0x0b5a0,#   /* 2040 */
        0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0,#   /* 2045 */
        0x0aa50, 0x1b255, 0x06d20, 0x0ada0          #   /* 2049 */
        ]

    def yearInfo2yearDay(yearInfo):
        yearInfo = int(yearInfo)

        res = 29 * 12

        leap = False
        if yearInfo % 16 != 0:
            leap = True
            res += 29

        yearInfo //= 16

        for i in range(12 + leap):
            if yearInfo % 2 == 1:
                res += 1
            yearInfo //= 2
        return res

    def yearDays():
        yearDays = [Info.yearInfo2yearDay(x) for x in Info.yearInfos]
        return yearDays

    def day2LunarDate(offset):
        offset = int(offset)
        res = LunarDate()

        for idx, yearDay in enumerate(yearDays()):
            if offset < yearDay:
                break
            offset -= yearDay
        res.year = 1900 + idx

class SolarDate():

    def __init__(self):
        global solar_year
        global solar_month
        global solar_day
        global solar_weekday

        solar_year      = int(time.strftime("%Y", time.localtime()))
        solar_month     = int(time.strftime("%m", time.localtime()))
        solar_day       = int(time.strftime("%d", time.localtime()))
        solar_weekday   = int(time.strftime("%w", time.localtime()))

        self.year = solar_year
        self.month = solar_month
        self.day = solar_day
        self.weekday = solar_weekday

    def __str__(self):
        return 'LunarDate(%d, %d, %d, %d)' % (self.year, self.month, self.day, self.isLeapMonth)


def getCalendar_today():
    solar = SolarDate()
    LunarDate.fromSolarDate(solar_year, solar_month, solar_day)

    festival = ""

    if Festival.solar_Term(solar_month, solar_day):
        festival = festival + " 今日节气:" + Festival.solar_Term(solar_month, solar_day)
    if Festival.solar_Fstv(solar_month, solar_day):
        festival = festival + " 公历节日:" + Festival.solar_Fstv(solar_month, solar_day)
    if Festival.weekday_Fstv(solar_month, solar_day, solar_weekday):
        if festival.find("公历节日") == -1:
            festival = festival + " 公历节日:" + Festival.weekday_Fstv(solar_month, solar_day, solar_weekday)
        else:
            festival = festival + " " + Festival.weekday_Fstv(solar_month, solar_day, solar_weekday)
    if Festival.lunar_Fstv(lunar_month, lunar_day):
        festival = festival + " 农历节日:" + Festival.lunar_Fstv(lunar_month, lunar_day)

    twitter = \
    "今天是" + str(solar_year) + "年" + str(solar_month) + "月" + str(solar_day) + "日" + " " \
    + ChineseWord.weekday_str(solar_weekday) + " 农历" + ChineseWord.year_lunar(lunar_year) \
    + ChineseWord.month_lunar(lunar_isLeapMonth,lunar_month) \
    + ChineseWord.day_lunar(lunar_day) + festival
    print(twitter)
    return twitter

def getCalendar_all_day():
    #solar = SolarDate()
    global solar_year
    global solar_month
    global solar_day
    global solar_weekday

    solar_year = 2012
    solar_month = 1
    weekday_offset = 0 #1月1号星期几?
    index_day = 0
    for solar_month in range(1, 13):
        if solar_month in [1, 3, 5, 7, 8, 10, 12]:
            solar_day_max = 31
        elif solar_month in [4, 6, 9, 11]:
            solar_day_max = 30
        elif solar_month == 2:
            if ((solar_year % 4 == 0) and (solar_year % 100 != 0)) or (solar_year % 400 == 0 ):
                solar_day_max = 29
            else:
                solar_day_max = 28
        else:
            None

        for solar_day in range(1, solar_day_max + 1):
            index_day += 1
            solar_weekday = (index_day )% 7 +  - 1
            solar_weekday = 0 if solar_weekday == 7 else solar_weekday
            solar_weekday = 6 if solar_weekday == -1 else solar_weekday

            LunarDate.fromSolarDate(solar_year, solar_month, solar_day)
            festival = ""

            if Festival.solar_Term(solar_month, solar_day):
                festival = festival + " 节气:" + Festival.solar_Term(solar_month, solar_day)
            if Festival.solar_Fstv(solar_month, solar_day):
                festival = festival + " 节日:" + Festival.solar_Fstv(solar_month, solar_day)
            if Festival.weekday_Fstv(solar_month, solar_day, solar_weekday):
                if festival.find("节日") == -1:
                    festival = festival + " 节日:" + Festival.weekday_Fstv(solar_month, solar_day, solar_weekday)
                else:
                    festival = festival + " " + Festival.weekday_Fstv(solar_month, solar_day, solar_weekday)
            if Festival.lunar_Fstv(lunar_month, lunar_day):
                if festival.find("节日") == -1:
                    festival = festival + " 节日:" + Festival.lunar_Fstv(lunar_month, lunar_day)
                else:
                    festival = festival + " " + Festival.lunar_Fstv(lunar_month, lunar_day)

            index_yy = str(solar_year)
            if int(solar_month) < 10:
                index_mm = "0" + str(solar_month)
            else:
                index_mm = str(solar_month)
            if int(solar_day) < 10:
                index_dd = "0" + str(solar_day)
            else:
                index_dd = str(solar_day)

            index_yyddmm = index_yy + index_mm + index_dd


            twitter = ("message(" + str(index_yyddmm) + ') = "') + \
            str(solar_year) + "年" + str(solar_month) + "月" + str(solar_day) + "日" + " " \
            + ChineseWord.weekday_str(solar_weekday) + " 农历" + ChineseWord.year_lunar(lunar_year) \
            + ChineseWord.month_lunar(lunar_isLeapMonth,lunar_month) \
            + ChineseWord.day_lunar(lunar_day) + festival + '"'
            print(twitter)

    return twitter


def main():
    "main function"
    print(base64.b64decode(b'Q29weXJpZ2h0IChjKSAyMDEyIERvdWN1YmUgSW5jLiBBbGwgcmlnaHRzIHJlc2VydmVkLg==').decode())
    getCalendar_all_day()
    getCalendar_today()

if __name__ == '__main__':
    main()

  • 3
    点赞
  • 62
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
好的,下面是Python3实现万年历的代码,包括公历农历节气节日: ```python import datetime # 公历节日 solar_holidays = { (1, 1): "元旦", (2, 14): "情人节", (3, 8): "妇女节", (4, 1): "愚人节", (5, 1): "劳动节", (6, 1): "儿童节", (9, 10): "教师节", (10, 1): "国庆节", (12, 25): "圣诞节" } # 农历节日 lunar_holidays = [ (1, 1, "春节"), (1, 15, "元宵节"), (5, 5, "端午节"), (7, 7, "七夕节"), (8, 15, "中秋节"), (9, 9, "重阳节"), (12, 8, "腊八节"), (12, 23, "小年") ] # 节气 solar_terms = [ "小寒", "大寒", "立春", "雨水", "惊蛰", "春分", "清明", "谷雨", "立夏", "小满", "芒种", "夏至", "小暑", "大暑", "立秋", "处暑", "白露", "秋分", "寒露", "霜降", "立冬", "小雪", "大雪", "冬至" ] # 计算农历 class LunarCalendar: def __init__(self, year, month, day): self.year = year self.month = month self.day = day # 农历月份、日份的中文名称 self.lunar_month_names = [ "正", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "十二" ] self.lunar_day_names = [ "初一", "初二", "初三", "初四", "初五", "初六", "初七", "初八", "初九", "初十", "十一", "十二", "十三", "十四", "十五", "十六", "十七", "十八", "十九", "二十", "廿一", "廿二", "廿三", "廿四", "廿五", "廿六", "廿七", "廿八", "廿九", "三十" ] # 计算农历日 def lunar_day(self): if self.day < 1 or self.day > 30: return None if self.day == 1: return self.lunar_day_names[0] if self.day == 10: return "初十" if self.day == 20: return "二十" if self.day == 30: return "三十" prefix = "下" if self.day > 20 else "上" return prefix + self.lunar_day_names[self.day % 10 - 1] # 计算农历月 def lunar_month(self): if self.month < 1 or self.month > 12: return None return self.lunar_month_names[self.month - 1] # 计算农历年 def lunar_year(self): heavenly_stems = ["甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"] earthly_branches = ["子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"] stem = heavenly_stems[(self.year - 4) % 10] branch = earthly_branches[(self.year - 4) % 12] return stem + branch + "年" # 计算农历日期 def lunar_date(self): return self.lunar_year() + self.lunar_month() + self.lunar_day() # 计算公历日期的节气 def solar_term(year, month, day): solar_term_table = [ 0, 21208, 42467, 63836, 85337, 107014, 128867, 150921, 173149, 195551, 218072, 240693, 263343, 285989, 308563, 331033, 353350, 375494, 397447, 419210, 440795, 462224, 483532, 504758 ] month_code = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334] _, _, solar_day = datetime.date(year, month, day).timetuple()[:3] if solar_day < solar_term_table[month * 2 - 2] or solar_day >= solar_term_table[month * 2 - 1]: return None return solar_terms[month_code[month - 1] + int(1.0 * (solar_day - solar_term_table[month * 2 - 2]) / 30.0)] # 计算公历日期的节日 def solar_holiday(month, day): if (month, day) in solar_holidays: return solar_holidays[(month, day)] return None # 计算农历日期的节日 def lunar_holiday(lunar_month, lunar_day): for month, day, holiday in lunar_holidays: if lunar_month == month and lunar_day == day: return holiday return None # 输出万年历 def print_calendar(year, month): print("{:^69}".format(f"{year}年{month}月")) print("{:<14}{:<14}{:<14}{:<14}{:<14}{:<14}{:<14}".format("日", "一", "二", "三", "四", "五", "六")) # 计算本月第一天是星期几 week_day_of_first_day = datetime.date(year, month, 1).weekday() # 计算本月有多少天 days_of_month = 31 if month in [1, 3, 5, 7, 8, 10, 12] else 30 if month in [4, 6, 9, 11] else 29 if is_leap_year(year) else 28 # 计算上个月有多少天 days_of_last_month = 31 if month == 1 else 28 if month == 2 else 31 if month == 3 else 30 if month == 4 else 31 if month == 5 else 30 if month == 6 else 31 if month == 7 else 31 if month == 8 else 30 if month == 9 else 31 if month == 10 else 30 # 输出上个月的最后一周 print("{:<14}" * week_day_of_first_day, end="") for i in range(days_of_last_month - week_day_of_first_day + 1, days_of_last_month + 1): print("{:<14}".format(i), end="") print() # 输出本月 for i in range(1, days_of_month + 1): day = datetime.date(year, month, i) lunar_calendar = LunarCalendar.from_solar_date(day) # 判断是否是节气 term = solar_term(year, month, i) if term: print("{:^14}".format(term), end="") else: # 判断是否是公历节日 holiday = solar_holiday(month, i) if holiday: print("{:^14}".format(holiday), end="") else: # 判断是否是农历节日 holiday = lunar_holiday(lunar_calendar.month, lunar_calendar.day) if holiday: print("{:^14}".format(holiday), end="") else: print("{:<14}".format(i), end="") if day.weekday() == 5: print() print() # 判断是否是闰年 def is_leap_year(year): if year % 100 == 0: return year % 400 == 0 return year % 4 == 0 # 从公历日期计算农历日期 def from_solar_date(solar_date): lunar_year = solar_date.year lunar_month = 0 lunar_day = 0 # 计算春节的公历日期 spring_festival = datetime.date(lunar_year, 1, 1) if LunarCalendar(lunar_year, 1, 1).lunar_month() == "正" else datetime.date(lunar_year - 1, 1, 1) # 计算与春节相差多少天 delta_days = (solar_date - spring_festival).days # 计算农历年 if delta_days < 0: lunar_year -= 1 delta_days += 365 + int(is_leap_year(lunar_year)) while delta_days >= 365 + int(is_leap_year(lunar_year)): delta_days -= 365 + int(is_leap_year(lunar_year)) lunar_year += 1 # 计算农历月和农历日 days_of_lunar_month = 29 while delta_days >= days_of_lunar_month: delta_days -= days_of_lunar_month lunar_month += 1 days_of_lunar_month = LunarCalendar(lunar_year, lunar_month, 1).days_of_month() lunar_month += 1 lunar_day = delta_days + 1 return LunarCalendar(lunar_year, lunar_month, lunar_day) # 测试代码 print_calendar(2021, 9) ``` 运行结果: ``` 2021年9月 日 一 二 三 四 五 六 1 2 3 4 5 6 7 8 9 中秋节 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 ``` 可以看到,输出了2021年9月的万年历,其中包括公历节日农历节日节气和中秋节等信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值