Things like this are done through OrderedDataStores. A reminder that you should generally try things out yourself before posting threads: this is not a do-my-work category.
When a player joins, you log the current time from os.time preferably in a dictionary. When they leave, you will also grab the current time but subtract the time they joined from this new value to get how long they were on. From here, you can call IncrementAsync on the player’s UserId for the key and that difference of time as the value. Ideally you shouldn’t save if this time is <6 seconds because of DataStore limitations.
As in when you want to update the leaderboard either initially or across a certain time interval, you’ll use GetSortedAsync to get a DataStorePages object. This pages object will contain the keys and values in the OrderedDataStore in numeric order (all values must be integers). You can then iterate through the pages object and display keys and values as necessary.
Since OrderedDataStores only accept integers for values and os.time returns seconds, as far as data storage goes, you’ll only be working with seconds in terms of integers. So, to get the format you see in the image, you will convert these seconds into appropriate times and make a string out of them. I personally have no clue how to do this so I’d appreciate some support here, but to take a stab…
local function breakDownSeconds(seconds)
local breakDown = {days = 0, hours = 0, minutes = 0, seconds = 0}
breakDown.seconds = seconds%60
breakDown.minutes = math.floor(seconds/60)%60
breakDown.hours = math.floor(seconds/3600)%24
breakDown.days = math.floor(seconds/86400)
return breakDown
end
From here, since you’ve got a table, you can use this to help you form a time string. If there’s a non-zero value for a key, concatenate it to a blank string with the value first and then the key second. You may need a secondary array to help you determine iteration order. Example…
local ITER_ORDER = {"days", "hours", "minutes", "seconds"}
local timeBreakDownForUser = breakDownSeconds(playerPageEntry.value)
local timeInGameString = ""
for _, key in ipairs(ITER_ORDER) do
local value = timeBreakDownForUser[key]
-- Should at least have *something* there
if value > 0 and key ~= "seconds" then
-- Use non-plurals if you really care about singular values, then
-- concatenate an "s" if the value ~= 1
local valueString = value .. key
-- Plural example with current layout
-- local valueString = value .. (value == 1 and key:sub(1, key:len() - 1) or key)
timeInGameString = timeInGameString .. valueString
end
end
While I can’t just give you a system here, hopefully the explanation and the code samples here give you an idea of what you might be looking to do here.