Issue with timer system

I am looking to create a timer system to track the time for a player to reach point A to B. While the basic fundamentals work properly, the time itself does not. Passing tick to the server and tracking the elapsed time creates a discrepancy due to client timezones. os.time also produces unwanted results as I am looking to achieve millisecond-precision.

-- Client
remotes.Events.StartTimer:FireServer(tick())
-- Server
remotes.Events.StartTimer.OnServerEvent:Connect(function(player, t)
    RunService.RenderStepped:Connect(function()
        local elapsed = math.floor((tick() - t) * 1000) / 1000
        print(elapsed) -- outputs inaccurate time based on player's timezone
    end)
end)

What would I be able to do to achieve a millisecond-precise timer regardless of the player’s timezone?

I would start and stop the timer event on the Server rather than the client. Add the Players in a table at the Start event and remove on the End event.:

-- Server
local playerStartTimes = {}
remotes.Events.StartTimer.OnServerEvent:Connect(function(player)
        playerStartTimes[player] = tick.os
end)

remotes.Events.EndTimer.OnServerEvent:Connect(function(player)
        local playerEndTime = tick.os
        local timeTaken = playerEndTime - playerTimes[player]
        print(player, timeTaken )
end)

Obviously needs an End event sent from the client.

This could be more optimal, however I prefer to pass it from the client to avoid any noticeable delays from the timer on the server.

Are you looking for millisecond timing? A client firing an event to the server should really be equivalent to the ping time (give or take a few milliseconds for processing). Alternatively, if you are using Touch events, the trigger them on the server.

You could calculate the timezone difference first, store it on the server in a list and then use that to remove the difference.

-- Server

local timezones = {};

remotes.Events.StartTimer.OnServerEvent:Connect(function(player, t)
    if (timezones[player.Name] == nil) then
        timezones[player.Name] = tick() - t -- timezone difference
    end
    RunService.RenderStepped:Connect(function()
        local elapsed = math.floor((tick() - t - timezones[player.Name]) * 1000) / 1000
        print(elapsed) -- outputs inaccurate time based on player's timezone
    end)
end)

Note - not tested - don’t have access to studio.