用pandas读取工时数据需统一为CSV或指定openpyxl引擎读Excel,标准化列名、转datetime并处理异常,按员工+日期聚合计算工时、迟到、缺勤,清洗姓名部门、添加业务规则与日志校验。

直接说结论:用 pandas 读取打卡/工时表(Excel 或 CSV),按员工+日期聚合,再用 groupby + agg 计算总工时、迟到次数、缺勤天数,比写 Excel 公式或手动汇总快 10 倍以上,且可每天定时运行。
怎么读入不同格式的原始工时数据?
实际中数据来源五花八门:钉钉导出是 Excel(.xlsx),企业微信可能是 CSV,有些部门还交手填的表格截图——先聚焦能程序化处理的部分。
- 优先统一为 CSV:用
pd.read_csv("attendance.csv")最稳定;若必须读 Excel,加engine="openpyxl"避免xlrd不支持新格式报错 - 关键列名要标准化:哪怕原始表叫“姓名”“上班时间”“下班时间”,读入后立刻重命名为
"name"、"check_in"、"check_out",后续逻辑才不依赖中文列名 - 时间字段必须转
datetime:用pd.to_datetime(df["check_in"], errors="coerce"),errors="coerce"会把乱码时间转成NaT,避免整个脚本崩溃
如何准确计算每人每日实际工时?
不能简单用 check_out - check_in —— 没考虑午休、打卡异常、跨天加班等现实情况。得加业务规则:
- 默认午休 1 小时:用
(df["check_out"] - df["check_in"]) - pd.Timedelta("1H") - 剔除无效记录:
df["check_in"].notna() & df["check_out"].notna()才参与计算 - 跨天加班(如 22:00 打卡到次日 02:00)需特殊处理:先判断
check_out ,再加 24 小时修正,否则工时变负数 - 结果统一转为“小时”浮点数:
.dt.total_seconds() / 3600,方便后续 sum/mean
怎样统计迟到、缺勤、月度总工时?
核心是用 groupby 分组后多维度聚合,避免写循环:
图片提示词生成器?不止如此。 马甲系统 —— 把脑海中的画面,翻译成AI能理解的专业表达。 用得越多,它越懂你:首次需要多问几句确认方向,用久了几乎一说就懂。 用得越多,它越快:缓存机制让后续对话越来越省。 RAG进化:成功案例持续入库,越跑越聪明。 输入「新手指南」查看完整功能介绍
立即学习“Python免费学习笔记(深入)”;
df.groupby("name").agg(
total_hours=("work_hours", "sum"),
days_worked=("date", "nunique"),
late_count=("is_late", "sum"), # is_late 是布尔列:check_in > "09:00"
absent_days=("date", lambda x: 22 - x.nunique()) # 假设当月应出勤 22 天
)-
is_late要提前生成:用df["check_in"].dt.time > datetime.time(9, 0),注意别用字符串比较("09:05" > "09:00" 虽然对,但时区/格式一变就错) - 缺勤天数 = 应出勤天数 − 实际打卡天数,别直接数空值——员工某天只打了下班卡也算出勤
- 如果需要导出带样式的 Excel 报表,用
openpyxl引擎配合ExcelWriter,但别在统计逻辑里混样式代码,先保证数据准
为什么定时跑脚本后数据常“看起来对但实际错”?
最大陷阱是原始数据没清洗干净:比如“张三”和“张叁”被当两人,“测试部”和“测试一部”分属不同部门导致汇总失真。
- 姓名去空格、统一全角/半角:
df["name"] = df["name"].str.strip().str.replace(" ", " ") - 部门名做映射字典,合并别名:
df["dept"] = df["dept"].map({"测试一部": "测试部", "研发二组": "研发部"}) - 每次运行前加校验:打印
df["work_hours"].describe(),若 75% 分位数是 0 或负数,说明时间解析出问题了 - 别省略日志:用
print(f"已处理 {len(df)} 条记录,覆盖 {df['date'].nunique()} 天"),比任何文档都管用
真正难的不是写代码,是持续识别数据里的“人话例外”——比如销售岗弹性打卡、产线员工按班次不算小时、实习生不计考勤。这些规则得沉到代码注释里,而不是靠同事口头告诉你。

















