怎样实现考勤统计脚本

wen 实用脚本 28

本文目录导读:

怎样实现考勤统计脚本

  1. 基础版 - Python 脚本
  2. Shell 脚本版本(Linux)
  3. 数据库版本(SQL)
  4. 使用建议

我来帮你设计一个考勤统计脚本,以下是几种常见实现方式:

基础版 - 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;

使用建议

  1. 数据准备:确保考勤数据格式统一,包含姓名、日期、打卡时间等信息
  2. 定时执行:可以使用 cron 定时任务自动执行统计
  3. 异常处理:添加缺失打卡、重复打卡等异常情况的处理
  4. 可视化:结合 matplotlib 等库生成图表
  5. 扩展功能:添加加班统计、请假处理等

根据你的具体需求(数据格式、系统环境、统计要求),选择最适合的实现方式。

抱歉,评论功能暂时关闭!