calendar 模块是 Python 标准库的一部分,它提供了与日历相关的各种功能,比如生成文本日历、查找日期、处理星期几等,对于需要处理日期、安排任务、生成报表等应用场景,这个模块非常有用。
模块概述与核心概念
calendar 模块主要围绕两个核心概念展开:
-
星期几的表示:
- 在
calendar模块中,星期几被表示为整数,从 0(星期一) 到 6(星期日),这与欧洲许多国家的习惯一致。 - 这与 Python 内置的
datetime模块不同,datetime模块中的weekday()方法返回的是 0(星期一) 到 6(星期日),而isoweekday()方法返回的是 1(星期一) 到 7(星期日),使用时需要注意区分。
- 在
-
月份的表示:
- 月份被表示为整数,从 1(一月) 到 12(十二月),这符合常规认知。
主要功能与函数详解
calendar 模块的功能非常丰富,我们将其分为几大类来讲解。
A. 生成日历
这是 calendar 模块最核心的功能,可以生成多种格式的日历。
calendar.calendar(year, w=2, l=1, c=6, m=3)
生成一个指定年份的整年日历,格式为多行文本。
- 参数:
year(int): 要生成的年份。w(int): 每个日期字符的宽度,默认为 2。l(int): 每周行数,默认为 1。c(int): 月份之间的间隔字符数,默认为 6。m(int): 每行显示的月份数,默认为 3。
示例:
import calendar # 生成 2025 年的日历,每行显示 3 个月 cal_2025 = calendar.calendar(2025, m=3) print(cal_2025)
输出会是一个格式化的文本,展示 2025 年全年 12 个月的日历。
calendar.month(year, month, w=2, l=1)
生成指定年份和月份的单月日历。
- 参数:
year(int): 年份。month(int): 月份 (1-12)。w(int): 每个日期字符的宽度,默认为 2。l(int): 每周行数,默认为 1。
示例:
import calendar # 生成 2025 年 10 月的日历 oct_2025 = calendar.month(2025, 10) print(oct_2025)
输出:
October 2025
Mo Tu We Th Fr Sa Su
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 31
calendar.monthcalendar(year, month)
生成一个指定月份的“矩阵”表示,非常适合程序处理。
- 返回值: 一个“周列表”的列表,每个子列表代表一周,包含 7 个整数,如果某天不属于当前月份,则用
0表示。
示例:
import calendar # 获取 2025 年 10 月的日历矩阵 oct_matrix = calendar.monthcalendar(2025, 10) print(oct_matrix)
输出:
[[0, 0, 0, 0, 0, 1, 2], # 第一周,前5天是上个月的,用0填充
[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],
[31, 0, 0, 0, 0, 0, 0]] # 最后一周,后6天是下个月的,用0填充
B. 日期与星期信息查询
这些函数用于获取特定日期的星期信息。
calendar.weekday(year, month, day)
返回指定日期是星期几(0-6,0代表星期一)。
示例:
import calendar
# 查询 2025年10月1日 是星期几
# 0=周一, 1=周二, ..., 6=周日
day_of_week = calendar.weekday(2025, 10, 1)
print(f"2025年10月1日是星期: {day_of_week}") # 输出 6,即星期日
calendar.monthrange(year, month)
返回一个元组 (first_weekday, number_of_days)。
first_weekday: 该月第一天是星期几(0-6)。number_of_days: 该月的总天数。
示例:
import calendar
# 查询 2025年10月 的信息
first_day, days_in_month = calendar.monthrange(2025, 10)
print(f"2025年10月的第一天是星期: {first_day}") # 输出 6 (周日)
print(f"2025年10月共有: {days_in_month} 天") # 输出 31
C. 判断闰年和工作日
calendar.isleap(year)
判断指定年份是否为闰年。
示例:
import calendar print(calendar.isleap(2025)) # True print(calendar.isleap(2025)) # False
calendar.leapdays(year1, year2)
返回 year1 到 year2 之间(不包括 year2)的闰年总数。
示例:
import calendar
# 计算 2000 到 2025 年之间的闰年数
num_leap_years = calendar.leapdays(2000, 2025)
print(f"2000到2025年之间有 {num_leap_years} 个闰年") # 输出 5 (2000, 2004, 2008, 2012, 2025)
calendar.isweekday(day)
- 注意: 这个函数在 Python 3.9 中被弃用,并在 Python 3.11 中被移除。
- 替代方案: 使用
day < 5或day in range(5)来判断是否为工作日(周一至周五)。 - 旧功能 (Python < 3.9): 判断一个
weekday(0-6) 是否为工作日。
示例 (Python 3.9+):
import calendar
def is_weekday_pythonic(day):
"""使用推荐的方式判断是否为工作日"""
return day < 5
print(is_weekday_pythonic(0)) # True (周一)
print(is_weekday_pythonic(5)) # False (周六)
D. 常量与日期名称
calendar 模块提供了一些有用的常量,避免硬编码。
calendar.day_name 和 calendar.day_abbr
calendar.day_name: 一个列表,包含星期几的全名(从 "Monday" 开始)。calendar.day_abbr: 一个列表,包含星期几的缩写(从 "Mon" 开始)。
示例:
import calendar
# 获取星期三的全名和缩写
wednesday_full = calendar.day_name[2]
wednesday_abbr = calendar.day_abbr[2]
print(f"星期三的全名: {wednesday_full}") # Wednesday
print(f"星期三的缩写: {wednesday_abbr}") # Wed
注意: 索引 2 对应的是星期三,因为 0 是星期一。
calendar.month_name 和 calendar.month_abbr
calendar.month_name: 一个列表,包含月份的全名,索引0是一个空字符串,索引1到12是月份名。calendar.month_abbr: 一个列表,包含月份的缩写,索引0是一个空字符串。
示例:
import calendar
# 获取十月和十一月的全名和缩写
october_full = calendar.month_name[10]
november_abbr = calendar.month_abbr[11]
print(f"十月: {october_full}") # October
print(f"十一月缩写: {november_abbr}") # Nov
E. 其他实用函数
calendar.timegm(tuple)
timegm() 是 calendar 模块中的一个函数,它实际上是 calendar.timegm,但更常见的用法是直接从 time 模块导入 timegm,它执行与 time.gmtime() 相反的操作:将 UTC 时间戳(从纪元开始的秒数)转换为 time.struct_time。
示例:
import calendar
import time
# 假设我们有一个时间戳
timestamp = 1696118400 # 2025年10月1日 00:00:00 UTC
# 使用 calendar.timegm 将 struct_time 转回时间戳
# (注意:通常我们从 time 模块导入 timegm)
# 这里演示其反向操作,gmtime 将时间戳转为 struct_time
utctuple = time.gmtime(timestamp)
print(f"Struct_time: {utctuple}")
# 再用 timegm 转回时间戳
original_timestamp = calendar.timegm(utctuple)
print(f"转回的时间戳: {original_timestamp}")
注意: calendar.timegm 是 time.timegm 的别名,在实际编程中,直接 from time import timegm 更为常见。
综合应用示例
示例1:查找某个月份的所有周五
import calendar
def find_fridays(year, month):
"""查找指定年月中的所有周五"""
# 1. 获取该月的日历矩阵
month_matrix = calendar.monthcalendar(year, month)
fridays = []
# 2. 遍历每一周
for week in month_matrix:
# calendar 模块中,周五是 4 (0=周一, 4=周五)
if week[4] != 0: # 确保不是0(即不是其他月份的日期)
fridays.append(week[4])
return fridays
# 查找 2025 年 10 月的所有周五
fridays_in_oct = find_fridays(2025, 10)
print(f"2025年10月的所有周五是: {fridays_in_oct}")
# 输出: [6, 13, 20, 27]
示例2:打印一个简单的任务日历
import calendar
def print_task_calendar(year, month, tasks):
"""
打印一个带有任务的日历
tasks: 一个字典,键是 (day, task_name) 元组,值可以是任何信息
"""
print(calendar.month(year, month).center(20)) # 居中打印月份标题
print("-" * 20)
# 获取星期几的缩写
header = " ".join(calendar.day_abbr)
print(header.center(20))
print("-" * 20)
# 获取日历矩阵
month_matrix = calendar.monthcalendar(year, month)
for week in month_matrix:
week_str = ""
for day in week:
if day == 0:
week_str += " " # 三个空格对齐
else:
# 检查当天是否有任务
task_info = ""
for (task_day, task_name), _ in tasks.items():
if task_day == day:
task_info = f"({task_name[0]})" # 只取任务名首字母
break
# 日期占2位,任务信息占1位,共3个字符宽度
week_str += f"{day}{task_info:>2}" # 右对齐
week_str += " "
print(week_str)
print("-" * 20)
# 定义一些任务
my_tasks = {
(5, "Meeting"): "重要会议",
(15, "Project"): "项目截止",
(22, "Party"): "生日派对"
}
print_task_calendar(2025, 10, my_tasks)
输出会是一个类似下面这样的日历,有任务的日期后面会有标记:
October 2025
--------------------
Mo Tu We Th Fr Sa Su
1
2 3 4 5(M) 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21(P) 22
23 24 25 26 27 28 29
30 31
--------------------
(注:格式可能略有不同,取决于终端宽度)
calendar 与 datetime 的关系
calendar 和 datetime 是 Python 处理日期时间的两个核心模块,它们相辅相成:
datetime: 更侧重于表示一个具体的、精确到微秒的时间点(datetime对象)或时间段(timedelta对象),它是进行日期算术、比较、格式化的主力。calendar: 更侧重于日历的“宏观”视图,某月有多少天”、“某天是星期几”、“生成一个月的布局”等,它提供的是日历相关的结构和信息。
如何结合使用?
假设你想知道“今年的最后一个周五是哪天?”
-
用
calendar找出信息:- 用
calendar.monthrange(year, 12)获取12月的信息,得到该月有多少天。 - 用
calendar.weekday(year, 12, days_in_month)找出最后一天是星期几。 - 根据最后一天的星期几,倒推出最后一个周五的日期。
- 用
-
用
datetime创建和表示日期:- 一旦通过
calendar算出最后一个周五的日期(day = 29),就可以用datetime.date(year, 12, day)来创建一个标准的日期对象,方便后续处理或格式化输出。
- 一旦通过
示例:
import calendar
import datetime
year = 2025
# 1. 使用 calendar 找出信息
_, days_in_dec = calendar.monthrange(year, 12)
last_day_weekday = calendar.weekday(year, 12, days_in_dec)
# 从最后一天往前推,找到最后一个周五 (weekday=4)
# 如果最后一天是周五 (4),则天数差为0
# 如果最后一天是周六 (5),则天数差为1
# ...
# 如果最后一天是周一 (0),则天数差为5
days_to_subtract = (last_day_weekday - 4) % 7
last_friday_day = days_in_dec - days_to_subtract
# 2. 使用 datetime 创建日期对象
last_friday_date = datetime.date(year, 12, last_friday_day)
print(f"{year}年的最后一个周五是: {last_friday_date.strftime('%Y年%m月%d日')}")
# 输出: 2025年的最后一个周五是: 2025年12月29日
| 功能类别 | 核心函数/常量 | 描述 | 适用场景 |
|---|---|---|---|
| 生成日历 | calendar(), month(), monthcalendar() |
生成文本或矩阵格式的日历 | 打印月历、年历、为UI组件提供数据 |
| 日期查询 | weekday(), monthrange() |
查询某天是星期几、某月第一天和总天数 | 逻辑判断、安排任务、计算日期间隔 |
| 闰年判断 | isleap(), leapdays() |
判断闰年、计算闰年数量 | 日期计算、财务系统(处理2月29日) |
| 名称常量 | day_name, month_name |
获取星期和月份的全名/缩写 | 避免硬编码,生成国际化输出 |
| 辅助函数 | timegm() |
时间戳转换 | 处理 UTC 时间戳 |
最佳实践:
- 需要生成日历视图:首选
calendar模块。 - 需要精确的日期计算和操作:首选
datetime模块。 - 两者结合:当需要日历的宏观信息(如某月的天数)来进行精确的日期计算时,将它们结合使用,可以事半功倍。
希望这份详细的解析能帮助你完全掌握 Python 的 calendar 模块!
