为了数清还有几天到周末,我用python绘制了日历

devtools/2024/11/18 20:50:46/

日历的秘密

昨天,在看小侄子写作业的时候,发现了一个秘密:他在“演算纸”(计算数学题用的草纸)上画了非常多的日历。对此我感到了非常的困惑,“这是做什么的?”

后来,经过了我不懈的追问,小侄子终于说出了实情,“在学校太无聊,所以经常画日历,看看还有几天放假。”

哦!原来是这样!虽然这种行为不值得提倡,但是,小侄子想要放假的心情是可以理解的。所以,我决定帮帮他,研究一下怎么用python绘制出日历。

计算节假日

节假日

众所周知,一周有7天,其中周一到周五是工作日,周六周日是双休日。

每年元旦休息1天,春节休息3天,中秋,端午,清明节各休息1天,劳动节休息1天,国庆节休息3天,总共休息11天。

看起来,只要掌握了节日的规律,就可以知道假期了。但是,由于“调休”,周六周日也不总是休息日,其他工作日也可能变成休息日,所以,不能简单的这样做。

那么,要如何才能够计算出哪些日子是假日呢?答案是,必须要等到每年公布节假日才行。然后,根据公布的结果,进行手动标注。这听起来很麻烦,有没有什么更好的办法可以一劳永逸的解决问题呢?

使用中国日历库

安装:pip install chinesecalendar

升级:pip install -U chinesecalendar

中国日历是一个现有的库,可以方便的提供每一天是否是中国的节假日,是什么假日。其实现原理是,该日历库的作者为我们标注好了每一年的节假日,只需要调用即可。

python">import datetime
import calendar
import chinese_calendar as ccdef day_in_month(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)weekday = date.weekday()on_holiday, holiday_name = cc.get_holiday_detail(date)info.append({"day": f"{year}-{month}-{day}","weekday": weekday + 1,"on_holiday": on_holiday,"holiday_name": holiday_name})return infoprint(day_in_month(2024, 11))

不过需要注意的是:由于该库中的节假日都是作者添加的,所以,在不更新升级的情况下,节假日是不会增多的。例如,现在还没有公布2025年的节假日,那么该库就不能处理2025年的节假日。需要在该库更新以后,手动更新该库,才可以用上最新实现,这听起来不太友好。毕竟,如果在网络受限的环境中,或者没有及时更新,即使已经到了新的年份,旧有的程序也不能很好工作。

使用爬虫程序

另一种想法就是,通过发送网络请求,从网络信息上得到最新的节假日信息。这样,信息总是新的,而且,也不需要更新库,就可以一直使用旧有程序(假设网络地址持续有效,且结构没有发生更改)。

当然,我是非常不推荐这种方法的,与之前的方法不同,该方法虽然可以在不主动更新的情况下持续有效,但是没办法用于没有网络的环境。当然更重要的是,未经许可的爬虫行为并非是一种好的行为,如无必要应该尽量减少或者避免。

有一位作者也发布了一个库,用于爬虫的方式得到节假日信息,该库叫做china_calendar,爬取信息的地址选择的便民查询

python">import china_calendaris_holiday = china_calendar.is_holiday("2025-01-28")
print(is_holiday)

倒计时工具

计算时间差

虽然倒计时并不算是日历的一部分,但是可以快速帮助我们得知距离某天还有多久(比如说,还有几天放假)。首先,我们可以计算两个日期的时间差。

python">from datetime import datetimedef calculate_days_difference(date1, date2):difference = date2 - date1return difference.daysdate1 = datetime(2024, 11, 11)
date2 = datetime(2025, 1, 28)days_diff = calculate_days_difference(date1, date2)
print(f"两日期相差{days_diff}天")

计算倒计时

当然,如果是计算某个日期距离今天的时间差,就变成了倒计时功能了。

python">def countdown_to_date(target_date):today = datetime.now().date()difference = target_date.date() - todayreturn difference.daysdate = datetime(2025, 1, 28)
days_diff = countdown_to_date(date)
print(f"距离2025年除夕还有{days_diff}天")

绘制日历

画一个日历并不困难,但是想要画的好看,美观,需要考虑的就比较多了。不过,我们也可以用一个现成的日历实现,比如说fullcalendar,其可以在html的页面中,通过js代码,快速绘制一个功能丰富的日历。

我们可以通过script标签引入,然后,通过适当的js代码,就可以得到功能丰富的日历了,比如说,其官方网站提供的例子:

节假日信息的日历

结合之前的chinese_calendar库,我们就可以轻松实现一个带有节假日信息的日历了,我们将背景颜色设置为红色,当作假期。并且,通过flask作为后端,搭建一个web页面。

python">import datetime
import calendarimport chinese_calendar as cc
from flask import Flask, render_template, request, jsonifyapp = Flask(__name__)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": "#ff0000"})if holiday_name:info.append({"start": f"{year}-{month:02d}-{day:02d}","title": holiday_name})return infodef add_surrounding_year(year):info = []last_year = year - 1next_year = year + 1for month in range(1, 13):try:info.extend(add_holiday_info(last_year, month))info.extend(add_holiday_info(year, month))info.extend(add_holiday_info(next_year, month))except NotImplementedError as e:passreturn 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>

很好,现在,我们就得到了一个带有节假日信息的日历了!虽然看起来好像和常见的日历不太一样。不过正确且清晰。

 添加额外信息

日历上只有节假日信息,肯定不能让人满意,我们还可以在日历上添加一些自己的备注信息,让其在日历上显示出来。对于这个需求,我们不需要改动页面,只需要添加备注信息即可。

python">import datetime
import calendarimport chinese_calendar as cc
from flask import Flask, render_template, request, jsonifyapp = Flask(__name__)extra_info = [("2024-12-12", "双十二购物"),("2024-12-21", "冬至活动"),("2024-12-24", "约女神看电影"),("2024-12-25", "抓捕麋鹿老人")
]def add_extra_info():info = []for i in extra_info:info.append({"start": i[0],"title": i[1]})return infodef 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": "#ff0000"})return infodef add_surrounding_year(year):info = []last_year = year - 1next_year = year + 1for month in range(1, 13):try:info.extend(add_holiday_info(last_year, month))info.extend(add_holiday_info(year, month))info.extend(add_holiday_info(next_year, month))except NotImplementedError as e:passreturn infodef add_all_info(year):info = []info.extend(add_extra_info())info.extend(add_surrounding_year(year))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_all_info(year))

经过简单的修改以后,我们成功添加了备注信息。

引用与致谢

chinese_calendar的pypi地址

 china_calendar的pypi地址

 fullcalendar的官方地址

P.S.虽然我们成功绘制了日历,但是小侄子看了并不感到开心,“在学校里画日历,也是一种消磨时间的好办法,你都用程序画好了,我在学校干嘛?”,当然是要好好学习啊喂! 


http://www.ppmy.cn/devtools/135028.html

相关文章

如何使用正则表达式验证域名

下面是一篇关于如何使用正则表达式验证域名的教程。 如何使用正则表达式验证域名 简介 域名是互联网上网站的地址&#xff0c;每个域名由多个标签&#xff08;label&#xff09;组成&#xff0c;标签之间用点 . 分隔。域名规则有很多细节&#xff0c;但基本要求是&#xff1a…

【java】java通过s3访问ceph报错

1.报错信息、背景 工作中起了几个访问ceph的服务pod节点&#xff0c;一段时间后1个节点一直报错Unable to execute HTTP request: Timeout waiting for connection from pool&#xff0c;详细i信息如下图片&#xff0c;有且仅有1个节点报错&#xff0c;其他节点访问正常。看日志…

数据结构与算法分析模拟试题及答案5

模拟试题&#xff08;五&#xff09; 一、单项选择题&#xff08;每小题 2 分&#xff0c;共20分&#xff09; &#xff08;1&#xff09;队列的特点是&#xff08;   &#xff09;。 A&#xff09;先进后出 B&#xff09;先进先出 C&#xff09;任意位置进出 D&#xff0…

机器学习1

学习分类&#xff1a;监督学习、半监督学习、无监督学习、强化学习 监督学习&#xff1a;从有标签的训练数据中学习模型&#xff0c;然后对某个给定的新数据利用模型预测它的标签。 半监督学习&#xff1a;利用少量标注数据和大量无标注数据进行学习的模式 无监督学习&#…

unity小:shaderGraph不规则涟漪、波纹效果

实现概述 在本项目中&#xff0c;我们通过结合 Sine、Polar Coordinates 和 Time 节点&#xff0c;实现了动态波纹效果。以下是实现细节&#xff1a; 核心实现 Sine 波形生成&#xff1a; 使用 Sine 节点生成基本的波形。该节点能够创建周期性变化&#xff0c;为波纹效果提供…

4.1 Android NDK 简介

原生开发套件&#xff08;NDK&#xff09;是一套工具&#xff0c;使您能够在 Android 应用中使用 C/C 代码&#xff0c;并提供众多平台库&#xff0c;您可以使用这些平台库管理原生 activity 和访问实体设备组件&#xff0c;例如传感器和触控输入。如果您需要实现以下一个或多个…

Java-02 深入浅出 MyBatis - MyBatis 快速入门(无 Spring) POM Mapper 核心文件 增删改查

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 大数据篇正在更新&#xff01;https://blog.csdn.net/w776341482/category_12713819.html 目前已经更新到了&#xff1a; MyBatis&#xff…

Java结合ElasticSearch根据查询关键字,高亮显示全文数据。

由于es高亮显示机制的问题。当全文内容过多&#xff0c;且搜索中标又少时&#xff0c;就会出现高亮结果无法覆盖全文。因此需要根据需求手动替换。 1.根据es的ik分词器获取搜索词的分词结果。 es部分&#xff1a; //中文分词解析 post /_analyze {"analyzer":"…