calendar.monthrange()返回元组(weekday, days_in_month),第一个值0-6表示周一至周日,第二个值才是当月天数;直接取索引[1]即可获取天数,勿加1,且需结合weekday补前导空格生成完整日历。

calendar.monthrange() 返回的天数怎么用才不踩坑
直接用 calendar.monthrange(year, month) 获取某月第一天星期几和总天数,但容易忽略返回值是元组:(weekday, days_in_month)。第一个值是 0(周一)到 6(周日),不是 1–7;第二个值才是你要的天数。别写成 days = calendar.monthrange(2024, 2)[1] + 1——2 月只有 29 天,加 1 就错了一天。
常见错误:用这个结果直接做 for 循环 range(1, days+1),却忘了 weekday 偏移导致排班格子错位。正确做法是先补足前导空格(或 None),再填日期。
- 用
calendar.weekday(year, month, 1)单独查 1 号星期几更直观,返回值也是 0–6 - 如果要生成带完整周的二维列表(比如 6 行 × 7 列),必须按
calendar.monthcalendar(year, month)的逻辑处理:它自动补 0 占位,比手动算安全得多 - 注意闰年影响——
calendar.isleap(year)可提前校验,避免 2 月排班漏掉 29 号
用 calendar.TextCalendar 生成可读文本排班表的隐藏参数
calendar.TextCalendar 默认以周日开头,但国内排班习惯是周一开头。不改 firstweekday 参数,生成的表头就是 Su Mo Tu...,和实际排班表对不上。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 初始化时传
calendar.TextCalendar(firstweekday=calendar.MONDAY) -
formatmonth(year, month, w=3, l=1)中w是每列最小宽度(字符数),l是行高(空行数),调太小会导致日期挤在一起,看不清 - 别直接 print 输出——它带换行和空格,粘贴到 Excel 会错位;用
splitlines()拆成列表后逐行处理更可控 - 如果要插入班次标记(如 “早/中/夜”),不能往
formatmonth结果里硬塞字符串,得基于monthcalendar()返回的二维 int 列表操作
calendar.monthcalendar() 返回的二维列表怎么映射到真实班次
calendar.monthcalendar(year, month) 返回一个嵌套列表,每行是 7 个整数,0 表示该位置不属于当月(即上月/下月的占位),非零才是真实日期。这是排班逻辑的黄金输入源,但很多人直接当成纯数字矩阵处理,忽略了 0 的语义。
典型场景:给每个工作日分配班次,周末轮休。关键点在于区分“真实日期”和“占位符”:
- 遍历每行
week,再遍历day in week,只对day != 0的位置计算班次 - 用
calendar.weekday(year, month, day)判断是否周末(返回 5 或 6) - 班次循环可用
shifts = ["早", "中", "夜"]+shifts[day % len(shifts)],但注意:按日期取模会导致每月 1 号总是“早”,缺乏随机性;更合理的是用hash(f"{year}-{month}-{day}") % 3或预设轮班序列 - 输出时保留 0 占位,否则表格列宽会塌缩,对齐失效
生成 Excel 排班表时 calendar 和 openpyxl 怎么协作
calendar 模块只管日期结构,不负责写 Excel。硬拼字符串再用 openpyxl 写入容易错列——尤其当某月有 6 周时,monthcalendar() 返回 6 行,而默认只写 5 行就漏数据。
关键动作:
- 先用
cal = calendar.monthcalendar(year, month)拿到完整二维数据 - 创建表头:["周一", "周二", "周三", "周四", "周五", "周六", "周日"],写入第 1 行
- 从第 2 行开始写数据,每行对应
cal[i],每个单元格写day if day != 0 else "" - 班次列不要和日期混在一格里——单独加一列“班次”,用日期作为 key 查字典,避免格式混乱
- 注意时区:如果排班依赖本地时间,确保
year/month输入值已按本地时区解析,calendar 不处理时区
最易被忽略的是跨月边界:比如 12 月最后一周包含 1 月 1 日,monthcalendar(2024, 12) 末尾可能有 1、2、3,这些是明年日期,但仍在该列表中——排班逻辑必须识别并跳过,或打标注明。


















