农历日历
一个常见的带有农历的中国日历,通常包括农历日期,节日,与节气。
关于如何绘制日历,我们可以考虑继续使用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. 寒衣节并不是寒食节,寒食节是清明节之前,意为不使用烟火,只吃冷食,二者有很大的区别。