local datetime = {}

function datetime._format_time(t, fmt, mode)
    if mode == "12h" then
        local hour = t.hour
        local ampm = "AM"
        if hour == 0 then
            hour = 12
        elseif hour == 12 then
            ampm = "PM"
        elseif hour > 12 then
            hour = hour - 12
            ampm = "PM"
        end
        -- if fmt does not valid, use default format for 12h
        if not fmt or fmt == "" then
            fmt = "%02d:%02d:%02d %s"
        end
        return string.format(fmt, hour, t.min, t.sec, ampm)
    else
        -- if fmt does not valid, use default format for 24h
        if not fmt or fmt == "" then
            fmt = "%02d:%02d:%02d"
        end
        return string.format(fmt, t.hour, t.min, t.sec)
    end
end


-- Validate and return timezone offset (must be a number)
function datetime.get_offset(timezone_offset)
    local n = tonumber(timezone_offset)
    if n then return n end
    return 0
end

-- Returns a table with current UTC time
function datetime.utcnow()
    return os.date("!*t")
end

-- Returns a table with current local time
function datetime.localtime()
    return os.date("*t")
end


function datetime.now(timezone_offset)
    local o = datetime.get_offset(timezone_offset)
    if o == 0 then
        -- Local time
        return os.date("*t")
    else
        -- Current UTC time
        local utc = os.time(os.date("!*t"))
        -- Offset
        local target = utc + o * 3600
        return os.date("*t", target)
    end
end

-- mode: "12h" or "24h" (required)
-- fmt: string.format pattern, e.g. "%02d:%02d:%02d %s" for 12h, "%02d:%02d:%02d" for 24h
function datetime.format(timezone_offset, fmt, mode)
    assert(mode == "12h" or mode == "24h", "mode must be '12h' or '24h'")
    local o = datetime.get_offset(timezone_offset)
    local t = datetime.now(o)
    return datetime._format_time(t, fmt, mode)
end


-- Returns seconds since midnight for a given timezone offset
function datetime.seconds_since_midnight(timezone_offset)
    local t = datetime.now(timezone_offset)
    return t.hour * 3600 + t.min * 60 + t.sec
end

-- Returns weekday (0=Sunday, 6=Saturday) for a given timezone offset
function datetime.weekday(timezone_offset)
    local t = datetime.now(timezone_offset)
    return t.wday - 1
end

return datetime