绘制带有农历的日历,我发现了今天居然是传统节日?

农历日历

一个常见的带有农历的中国日历,通常包括农历日期,节日,与节气。

关于如何绘制日历,我们可以考虑继续使用fullcalendar,我们曾经使用过一次,具体可以参考之前的文章,python绘制日历

关于如何得到农历,节日,与节气,我们可以使用lunarcalendar库,如果你不了解这个,可以看之前的文章, python使用lunarcalendar

 那么现在,我们的思路很清晰了,需要将节日,节气,农历等信息,添加到日历上。

绘制日历

创建flask应用

import datetime
import calendar
from calendar import monthrange
import chinese_calendar as cc

from flask import Flask, render_template, request, jsonify

from lunarcalendar import Converter, Solar
from lunarcalendar.solarterm import solarterms
from lunarcalendar.festival import festivals


class LunarStr:
    months = ["正月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"]
    days = ["初一", "初二", "初三", "初四", "初五", "初六", "初七", "初八", "初九", "初十",
            "十一", "十二", "十三", "十四", "十五", "十六", "十七", "十八", "十九", "二十",
            "廿一", "廿二", "廿三", "廿四", "廿五", "廿六", "廿七", "廿八", "廿九", "三十"]

    @classmethod
    def from_year_month_day(cls, year, month, day):
        solar = Solar(year, month, day)
        lunar = Converter.Solar2Lunar(solar)
        return cls(lunar)

    def __repr__(self):
        return f"LunarStr(year={self.year}, month={self.month}, day={self.day})"

    def __init__(self, lunar):
        self.year = lunar.year
        self.month = lunar.month
        self.day = lunar.day
        try:
            self.month_str = self.months[lunar.month - 1]
            self.day_str = self.days[lunar.day - 1]
        except IndexError:
            raise ValueError("月份或日期超出有效范围!")
        if lunar.isleap:
            self.month_str = "闰" + self.month_str

    def get_calendar_date_str(self):
        if self.day == 1:
            return self.month_str
        else:
            return self.day_str

    def get_date_str(self):
        return self.month_str + self.day_str

app = Flask(__name__)


def get_fs_dict(year):

    lunar_dict = {}

    for st in solarterms:
        lunar_dict[str(st(year))] = st.get_lang("zh")

    for fest in festivals:
        lunar_dict[str(fest(year))] = fest.get_lang("zh")

    return lunar_dict

def add_lunar_info(year, month):
    info = []
    weekday, num_days = monthrange(year, month)
    fs_dict = get_fs_dict(year)
    for day in range(1, num_days + 1):
        lunar = Converter.Solar2Lunar(Solar(year, month, day))
        date_str = LunarStr(lunar).get_calendar_date_str()
        if str(datetime.date(year, month, day)) in fs_dict:
            date_str = fs_dict.get(str(datetime.date(year, month, day)))
        info.append({
            "start": str(datetime.date(year, month, day)),
            "title": date_str,
            "display": "background",
            "color": "#00000"
        })
    return info


def add_holiday_info(year, month):
    info = []
    days_in_month = calendar.monthrange(year, month)[1]
    for day in range(1, days_in_month + 1):
        date = datetime.datetime(year, month, day)
        on_holiday, holiday_name = cc.get_holiday_detail(date)
        if on_holiday:
            info.append({
                "start": f"{year}-{month:02d}-{day:02d}",
                "title": "",
                "display": "background",
                "backgroundColor": "#eb3152"
            })
    return info


def add_surrounding_year(year):
    info = []
    last_year = year - 1
    next_year = year + 1

    for year in [last_year, year, next_year]:
        for month in range(1, 13):
            try:
                info.extend(add_holiday_info(year, month))
                info.extend(add_lunar_info(year, month))

            except NotImplementedError as e:
                pass

    return info

@app.route("/")
def index():
    return render_template("index.html")


@app.route("/api/events")
def get_events():
    year = int(request.args.get("year"))
    return jsonify(add_surrounding_year(year))

添加index.html的页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>包括农历的日历</title>
    <script src='https://cdn.jsdelivr.net/npm/fullcalendar@6.1.15/index.global.min.js'></script>

    <style>
        #calendar {
            max-width: 900px;
            margin: 0 auto;
        }
    </style>
    <script>
        document.addEventListener('DOMContentLoaded', function() {
            var calendarEl = document.getElementById('calendar');

            var calendar = new FullCalendar.Calendar(calendarEl, {
              initialView: 'dayGridMonth',
              locale: 'zh-cn',

              datesSet: function(info) {
                  var year = info.start.getFullYear();
                  var month = ('0' + (info.start.getMonth())).slice(-2);

                  fetch('/api/events?year=' + year + '&month=' + month)
                    .then(response => response.json())
                    .then(events => {
                        calendar.removeAllEvents();
                        calendar.addEventSource(events);
                    })
                    .catch(error => console.error('Error fetching events:', error));
              }
            });

            calendar.render();
        });
    </script>
</head>
<body>
    <div id="calendar"></div>
</body>
</html>

日历显示

总结与发现

这个日历已经实现了我们希望的功能,但是由于直接引用了fullcalendar的背景事件,所以文字不是很清楚,如果希望有更好的表现效果,应该对页面样式进行更多的调整。

而从日历中我们可以看出,今天(2024年11月1日),还是寒衣节,所谓寒衣节,就是农历的十月一日,是传统的祭祀节日,过去人们通常会在这一天进行祭扫,纪念先人,也叫做,“送寒衣”。也有一种说法,寒衣节,清明节,中元节,并称为传统的“三大鬼节”。

不过,随着时间的发展,现在很多人已经对这个节日没有什么印象了,甚至从来都没听说过,这真是太不应该了。

P.S. 寒衣节并不是寒食节,寒食节是清明节之前,意为不使用烟火,只吃冷食,二者有很大的区别。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值