杰瑞科技汇

Python calendar模块有哪些核心功能与用法?

calendar 模块是 Python 标准库的一部分,它提供了与日历相关的各种功能,比如生成文本日历、查找日期、处理星期几等,对于需要处理日期、安排任务、生成报表等应用场景,这个模块非常有用。


模块概述与核心概念

calendar 模块主要围绕两个核心概念展开:

  1. 星期几的表示

    • calendar 模块中,星期几被表示为整数,从 0(星期一)6(星期日),这与欧洲许多国家的习惯一致。
    • 这与 Python 内置的 datetime 模块不同,datetime 模块中的 weekday() 方法返回的是 0(星期一)6(星期日),而 isoweekday() 方法返回的是 1(星期一)7(星期日),使用时需要注意区分。
  2. 月份的表示

    • 月份被表示为整数,从 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)

返回 year1year2 之间(不包括 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 < 5day 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_namecalendar.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_namecalendar.month_abbr

  • calendar.month_name: 一个列表,包含月份的全名,索引 0 是一个空字符串,索引 112 是月份名。
  • 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.timegmtime.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                 
--------------------

(注:格式可能略有不同,取决于终端宽度)


calendardatetime 的关系

calendardatetime 是 Python 处理日期时间的两个核心模块,它们相辅相成:

  • datetime: 更侧重于表示一个具体的、精确到微秒的时间点(datetime 对象)或时间段(timedelta 对象),它是进行日期算术、比较、格式化的主力。
  • calendar: 更侧重于日历的“宏观”视图,某月有多少天”、“某天是星期几”、“生成一个月的布局”等,它提供的是日历相关的结构和信息。

如何结合使用?

假设你想知道“今年的最后一个周五是哪天?”

  1. calendar 找出信息

    • calendar.monthrange(year, 12) 获取12月的信息,得到该月有多少天。
    • calendar.weekday(year, 12, days_in_month) 找出最后一天是星期几。
    • 根据最后一天的星期几,倒推出最后一个周五的日期。
  2. 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 模块!

分享:
扫描分享到社交APP
上一篇
下一篇