Python工时统计循环异常:重复显示员工总工时条目求助
解决工时表管理系统中员工总工时重复计算的问题
看起来你在计算员工总工时的时候踩了几个常见的逻辑坑,咱们一步步理清楚问题,然后给出更简洁可靠的实现方案。
现有代码的核心问题
从你的输出和代码来看,导致Chris总工时重复的原因主要有这几点:
- 重复遍历触发多次计算:你的
secondNameList包含重复的"Chris"条目,循环每遇到一次就会重新计算一次他的总工时,自然会生成多条重复记录。 - 变量引用与计算逻辑混乱:代码里
tdelta是外部变量,没有和当前遍历的员工条目绑定,而且totalMinutes和totalMinutesPerPerson混用(比如totalHoursPerPerson += totalMinutes // 60里的totalMinutes未定义),导致计算结果出错。 - 用
set去重治标不治本:set只能去除完全相同的字符串,但你的问题根源是循环逻辑错误,去重后反而会留下矛盾的计算结果(比如Chris既有9小时又有18小时的记录)。
优化方案
方案一:让数据库直接完成统计(推荐)
利用MySQL的分组和日期计算功能,直接从数据库获取每个员工的总工时,既高效又能避免前端逻辑错误,还能解决SQL注入风险:
修改SQL查询语句
SELECT FirstName, LastName, -- 计算每条记录的工时秒数,求和后转成时间格式 SEC_TO_TIME(SUM(TIMESTAMPDIFF(SECOND, StartTime, FinishTime))) AS TotalHours FROM Sheets WHERE DateTesting >= %s AND DateTesting <= %s GROUP BY FirstName, LastName;
Python端执行代码(参数化查询,避免SQL注入)
import datetime import mysql.connector # 假设已建立数据库连接 conn = mysql.connector.connect(host='your_host', user='your_user', password='your_pass', database='your_db') cursor = conn.cursor() # 使用参数化查询,绝对不要用字符串拼接传递参数! query = """ SELECT FirstName, LastName, SEC_TO_TIME(SUM(TIMESTAMPDIFF(SECOND, StartTime, FinishTime))) AS TotalHours FROM Sheets WHERE DateTesting >= %s AND DateTesting <= %s GROUP BY FirstName, LastName; """ # 传递日期参数 cursor.execute(query, (StartDate, EndDate)) results = cursor.fetchall() # 展示结果到UI for first_name, last_name, total_hours in results: print(f'{first_name} {last_name} did a total of {total_hours} Hours') self.labels.append(Label(myframe, text=f'Name: {first_name} {last_name} | Total Hours: {total_hours}')) self.labels[-1].grid(column=0, row=len(self.labels)-1) cursor.close() conn.close()
这个方案的优势:
- 数据库处理分组统计效率更高,减少Python端的计算负担
- 从根源避免循环逻辑错误
- 参数化查询彻底解决原代码的SQL注入风险
方案二:Python端分组计算总工时
如果必须在Python端处理数据,推荐用字典按员工全名分组累计工时,逻辑清晰且不易出错:
import datetime # 假设从数据库获取的原始记录列表 time_records = [('Chris', 'Gracey', '07:00', '16:30'), ('Chris', 'Gracey', '07:00', '16:30'), ('Rory', 'Gracey', '07:00', '16:30'), ('John', 'Smith', '07:00', '16:30')] FMT = '%H:%M' # 用字典存储每个员工的总分钟数,键为员工全名 employee_totals = {} for first_name, last_name, start_time, finish_time in time_records: # 计算单条记录的工时分钟数 start_dt = datetime.datetime.strptime(start_time, FMT) finish_dt = datetime.datetime.strptime(finish_time, FMT) delta = finish_dt - start_dt record_minutes = delta.total_seconds() // 60 # 累计到对应员工的总工时 full_name = f'{first_name} {last_name}' if full_name in employee_totals: employee_totals[full_name] += record_minutes else: employee_totals[full_name] = record_minutes # 转换为易读的格式并生成结果列表 totals_per_person = [] for name, total_min in employee_totals.items(): hours = total_min // 60 minutes = total_min % 60 totals_per_person.append(f'{name} did a total of {hours} Hours {minutes} Minutes') # 输出并展示 for line in totals_per_person: print(line) # UI展示逻辑 self.labels.append(Label(myframe, text=line)) self.labels[-1].grid(column=0, row=len(self.labels)-1)
这个方案的优势:
- 逻辑清晰,避免重复遍历和变量混用
- 直接按员工分组累计,不会生成重复记录
- 计算过程透明,便于调试和维护
内容的提问来源于stack exchange,提问作者Rory Gracey
相关产品推荐
相关产品推荐

