You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 09:01:55