Lua时间对象差值计算及日志分析问题求助
问题分析与解决方案
咱们先直击核心问题:你的时间计算逻辑出错,根源在于makeTimeStamp函数使用了无效的日期参数给os.time——Lua的os.time不接受year=0这种不存在的日期,会返回错误的时间戳甚至nil,直接导致后续的时间差计算完全失效。另外你的GetTimeDifference函数逻辑过于复杂,还存在多处bug(比如浮点数分割、跨小时/跨天处理逻辑错误)。
下面是分步修复方案:
1. 替换无效的时间转换函数
直接把HH:MM:SS格式的时间转换成当天0点开始的秒数,这样计算时间差既简单又准确,完全不需要依赖os.time:
-- 将"HH:MM:SS"转换为当天0点起的秒数 function timeToSeconds(timeStr) local hour, min, sec = string.match(timeStr, "(%d+):(%d+):(%d+)") return tonumber(hour) * 3600 + tonumber(min) * 60 + tonumber(sec) end
2. 修正主逻辑中的时长计算与统计
我重构了你的主函数,修复了登录记录判断、跨天处理、天数统计等问题,同时简化了代码结构:
function averageHoursPerWorker() local fh, err = io.open("log2.log") if err ~= nil then print(err) return end local totalHoursPerWorker = {} -- 每个worker的总工作时长(小时) local workerLoginTime = {} -- 保存当前未登出的worker登录时间 local workerActiveDayCount = {} -- 每个worker的活跃天数(注意:如果日志无日期,这里暂时按登出次数统计,需后续优化) -- 遍历日志每一行,用lines()更简洁 for line in fh:lines() do local parts = {} for part in string.gmatch(line, "%S+") do table.insert(parts, part) end local timeStr = parts[1] local workerId = parts[2] local action = parts[3] if action == 'log-in' then -- 记录当前worker的登录时间 workerLoginTime[workerId] = timeStr elseif action == 'log-out' then local loginTime = workerLoginTime[workerId] -- 处理无登录记录直接登出的异常情况 if not loginTime then print(string.format("警告:Worker %s 登出时无有效登录记录", workerId)) goto continue end -- 计算本次工作时长(秒),处理跨天情况 local loginSec = timeToSeconds(loginTime) local logoutSec = timeToSeconds(timeStr) local durationSec = logoutSec >= loginSec and (logoutSec - loginSec) or (logoutSec + 86400 - loginSec) local durationHours = durationSec / 3600 -- 累加总时长与天数 totalHoursPerWorker[workerId] = (totalHoursPerWorker[workerId] or 0) + durationHours workerActiveDayCount[workerId] = (workerActiveDayCount[workerId] or 0) + 1 -- 清空登录记录,允许该worker下次登录 workerLoginTime[workerId] = nil end ::continue:: end fh:close() -- 输出结果 print("Worker ID | 日均工作小时数") print("---------------------------") for workerId, totalHours in pairs(totalHoursPerWorker) do local dayCount = workerActiveDayCount[workerId] or 0 if dayCount == 0 then print(string.format("%s | 无有效天数记录", workerId)) else local avgHours = totalHours / dayCount print(string.format("%s | %.2f", workerId, avgHours)) end end end -- 调用函数计算结果 averageHoursPerWorker()
3. 关键优化点说明
- 跨天处理:如果登出时间的秒数小于登录时间(比如23:00登录,次日01:00登出),自动加上一天的秒数(86400)确保时长计算正确。
- 异常处理:新增了无登录记录直接登出的警告,避免程序崩溃或统计错误。
- 代码简化:用
fh:lines()遍历日志行,用or运算符简化变量初始化,逻辑更清晰。
重要提醒:关于天数统计的准确性
当前代码中workerActiveDayCount是按登出次数统计天数的,但这不符合实际场景(同一个worker一天内多次登录登出应该只算1天)。如果你的日志没有日期信息,建议修改日志格式,在时间列添加日期(比如2024-05-20 00:00:00),然后可以用一个集合来记录每个worker的活跃日期,实现准确的天数统计:
-- 假设日志时间格式为"YYYY-MM-DD HH:MM:SS",修改log-in逻辑: if action == 'log-in' then local dateStr, timeStr = string.match(parts[1], "(%d+-%d+-%d+) (%d+:%d+:%d+)") workerLoginTime[workerId] = timeStr -- 用table作为集合自动去重日期 if not workerActiveDays[workerId] then workerActiveDays[workerId] = {} end workerActiveDays[workerId][dateStr] = true end -- 后续计算天数时: local dayCount = 0 for _ in pairs(workerActiveDays[workerId]) do dayCount = dayCount + 1 end
内容的提问来源于stack exchange,提问作者riki
相关产品推荐
相关产品推荐

