本文目录导读:

我来帮你设计一个考勤统计脚本,以下是几种常见实现方式:
基础版 - Python 脚本
import pandas as pd
from datetime import datetime, time
import os
class AttendanceStats:
def __init__(self, data_file):
"""
初始化考勤统计
:param data_file: 考勤数据文件路径(CSV格式)
"""
self.data_file = data_file
self.df = pd.read_csv(data_file)
self._preprocess_data()
def _preprocess_data(self):
"""预处理数据"""
# 转换时间列
self.df['打卡时间'] = pd.to_datetime(self.df['打卡时间'])
self.df['日期'] = self.df['打卡时间'].dt.date
self.df['时间'] = self.df['打卡时间'].dt.time
def set_work_time(self, start_time="09:00", end_time="18:00"):
"""设置工作时间"""
self.work_start = datetime.strptime(start_time, "%H:%M").time()
self.work_end = datetime.strptime(end_time, "%H:%M").time()
def classify_attendance(self, time_record):
"""分类考勤状态"""
if time_record <= self.work_start:
return "正常"
elif time_record <= datetime.strptime("09:30", "%H:%M").time():
return "迟到"
else:
return "严重迟到"
def calculate_daily_stats(self):
"""计算每日统计"""
daily_stats = []
for date, group in self.df.groupby('日期'):
# 找出第一次和最后一次打卡
first_punch = group['时间'].min()
last_punch = group['时间'].max()
# 计算工作时长
if last_punch >= self.work_end:
work_hours = (datetime.combine(date, last_punch) -
datetime.combine(date, first_punch)).seconds / 3600
else:
work_hours = 0
daily_stats.append({
'日期': date,
'姓名': group['姓名'].iloc[0],
'上班打卡': first_punch,
'下班打卡': last_punch,
'状态': self.classify_attendance(first_punch),
'工作时长(小时)': round(work_hours, 2)
})
return pd.DataFrame(daily_stats)
def generate_monthly_report(self, month=None):
"""生成月度报告"""
if month:
self.df = self.df[self.df['打卡时间'].dt.month == month]
daily_stats = self.calculate_daily_stats()
# 汇总统计
report = []
for employee in self.df['姓名'].unique():
employee_data = daily_stats[daily_stats['姓名'] == employee]
report.append({
'姓名': employee,
'出勤天数': len(employee_data),
'迟到次数': len(employee_data[employee_data['状态'] != '正常']),
'平均工作时长': round(employee_data['工作时长(小时)'].mean(), 2),
'加班天数': len(employee_data[employee_data['工作时长(小时)'] > 8])
})
return pd.DataFrame(report)
def export_to_excel(self, output_file="考勤统计报告.xlsx"):
"""导出到Excel"""
monthly_report = self.generate_monthly_report()
with pd.ExcelWriter(output_file) as writer:
# 写入月度报告
monthly_report.to_excel(writer, sheet_name='月度统计', index=False)
# 写入每日明细
daily_stats = self.calculate_daily_stats()
daily_stats.to_excel(writer, sheet_name='每日明细', index=False)
print(f"报表已生成:{output_file}")
# 使用示例
if __name__ == "__main__":
# 准备测试数据
test_data = {
'姓名': ['张三', '张三', '李四', '李四'],
'打卡时间': [
'2024-01-15 08:55:00',
'2024-01-15 18:30:00',
'2024-01-15 09:15:00',
'2024-01-15 17:45:00'
]
}
# 创建测试文件
pd.DataFrame(test_data).to_csv('考勤数据.csv', index=False)
# 执行统计
stats = AttendanceStats('考勤数据.csv')
stats.set_work_time("09:00", "18:00")
stats.export_to_excel()
Shell 脚本版本(Linux)
#!/bin/bash
# 考勤统计脚本(适用于文本格式的打卡记录)
# 使用方法: ./attendance_stats.sh [数据文件] [月份]
DATA_FILE="${1:-attendance.txt}"
MONTH="${2:-$(date +%m)}"
OUTPUT_FILE="attendance_report_${MONTH}.txt"
# 检查文件是否存在
if [ ! -f "$DATA_FILE" ]; then
echo "错误: 数据文件 $DATA_FILE 不存在"
echo "用法: $0 [数据文件] [月份]"
exit 1
fi
# 初始化统计变量
declare -A attendance_count
declare -A late_count
declare -A absent_count
echo "====== 考勤统计报告 ======" > "$OUTPUT_FILE"
echo "月份: $MONTH" >> "$OUTPUT_FILE"
echo "生成时间: $(date)" >> "$OUTPUT_FILE"
echo "===========================" >> "$OUTPUT_FILE"
# 处理考勤数据(假设格式:姓名 日期 打卡时间)
while IFS=' ' read -r name date punch_time; do
# 只处理指定月份的数据
record_month=$(echo $date | cut -d'-' -f2)
if [ "$record_month" != "$MONTH" ]; then
continue
fi
# 计数
((attendance_count[$name]++))
# 判断迟到(假设上班时间是9:00)
if [[ "$punch_time" > "09:15" ]]; then
((late_count[$name]++))
fi
done < "$DATA_FILE"
# 生成报告
echo -e "\n出勤统计:" >> "$OUTPUT_FILE"
printf "%-10s %-10s %-10s %-10s\n" "姓名" "出勤" "迟到" "缺勤" >> "$OUTPUT_FILE"
echo "----------------------------------------" >> "$OUTPUT_FILE"
# 获取所有员工
employee_list=$(awk '{print $1}' "$DATA_FILE" | sort -u)
for employee in $employee_list; do
attendance=${attendance_count[$employee]:-0}
late=${late_count[$employee]:-0}
absent=$((20 - attendance)) # 假设每月工作日20天
printf "%-10s %-10d %-10d %-10d\n" \
"$employee" "$attendance" "$late" "$absent" >> "$OUTPUT_FILE"
done
echo -e "\n报告已生成: $OUTPUT_FILE"
数据库版本(SQL)
-- 创建考勤表
CREATE TABLE attendance (
id INT PRIMARY KEY AUTO_INCREMENT,
employee_id INT NOT NULL,
punch_time DATETIME NOT NULL,
punch_type ENUM('上班', '下班') DEFAULT '上班',
INDEX idx_employee_date (employee_id, punch_time)
);
-- 插入示例数据
INSERT INTO attendance (employee_id, punch_time, punch_type) VALUES
(1, '2024-01-15 08:50:00', '上班'),
(1, '2024-01-15 18:10:00', '下班'),
(2, '2024-01-15 09:20:00', '上班'),
(2, '2024-01-15 17:50:00', '下班');
-- 考勤统计查询
SELECT
e.name AS 姓名,
DATE(a.punch_time) AS 日期,
MIN(CASE WHEN a.punch_type = '上班' THEN a.punch_time END) AS 上班时间,
MAX(CASE WHEN a.punch_type = '下班' THEN a.punch_time END) AS 下班时间,
CASE
WHEN TIME(MIN(CASE WHEN a.punch_type = '上班' THEN a.punch_time END)) <= '09:00:00'
THEN '正常'
ELSE '迟到'
END AS 状态,
TIMESTAMPDIFF(
HOUR,
MIN(CASE WHEN a.punch_type = '上班' THEN a.punch_time END),
MAX(CASE WHEN a.punch_type = '下班' THEN a.punch_time END)
) AS 工作时长
FROM attendance a
JOIN employees e ON a.employee_id = e.id
WHERE MONTH(a.punch_time) = 1 -- 指定月份
GROUP BY e.name, DATE(a.punch_time);
-- 月度统计汇总
SELECT
e.name AS 姓名,
COUNT(DISTINCT DATE(a.punch_time)) AS 出勤天数,
SUM(CASE
WHEN TIME(MIN(CASE WHEN a.punch_type = '上班' THEN a.punch_time END)) > '09:00:00'
THEN 1 ELSE 0
END) AS 迟到次数,
AVG(TIMESTAMPDIFF(
HOUR,
MIN(CASE WHEN a.punch_type = '上班' THEN a.punch_time END),
MAX(CASE WHEN a.punch_type = '下班' THEN a.punch_time END)
)) AS 平均工作时长
FROM attendance a
JOIN employees e ON a.employee_id = e.id
WHERE MONTH(a.punch_time) = 1
GROUP BY e.name;
使用建议
- 数据准备:确保考勤数据格式统一,包含姓名、日期、打卡时间等信息
- 定时执行:可以使用 cron 定时任务自动执行统计
- 异常处理:添加缺失打卡、重复打卡等异常情况的处理
- 可视化:结合 matplotlib 等库生成图表
- 扩展功能:添加加班统计、请假处理等
根据你的具体需求(数据格式、系统环境、统计要求),选择最适合的实现方式。