Syncing the time on all servers

So I want time to be synced across servers. Meaning if its night time in one server and you join another it will still be night time. I have this which works but you can see it is not using MINUTES_IN_A_DAY. I want to be able to set that constant so that 24 hours will elapse in that amount of minutes but it would still be synced across servers. I am not that great at mathy stuff so any help would be appreciated!

local Lighting = game:GetService("Lighting")
local RunService = game:GetService("RunService")

local MINUTES_IN_A_DAY = 1

local scale = 4

RunService.Heartbeat:Connect(function(dt)
	local t = os.time() * scale
	t = t % (3600 * 24)
	
	Lighting:SetMinutesAfterMidnight(t)
end)
7 Likes
local MINUTES_IN_A_DAY = 1

local Increment = 24/(MINUTES_IN_A_DAY*60)
local Minute = (os.time() % 86400)*60

RunService.Heartbeat:Connect(function(dt)
    Minute = Minute + Increment
    Lighting:SetMinutesAfterMidnight(Minute)
end)

I got this which solves my problem but creates a new one. It is no longer synced across servers.

1 Like

The only simple way you could achieve this is if you set the time of day based on the current time somewhere in the world. So when the server starts you sync the time with os.time(), and every minute the time of day in the world should advance one minute.

local Minute = (os.time() % 86400/Increment)*60

This seems to fix it. I need to test a little more to be positive.

1 Like

This did not fix it, nevermind.

Switching the starting minute variable to this seems to fix the problem. It is kind of hard to test as I can’t think of a good method.

local Minute = ((os.time() % 86400)*60)*Increment
1 Like

The issue is not the starting time, the issue is that you are increment it at a rate faster than the real world. By doing this, older servers will be ahead of newer ones.

Add 1 minute to the time every minute in an infinite loop.

I figured out a great way to test this. Everything works! I hope this thread can help out anyone else with the same problem. https://gyazo.com/7bea645412af74f071c7a79563f7b72f

I don’t want the increment to be at real world speeds. I had the increment fine. I wanted the increment so that 24 hours would be in one minute. The real problem was just the starting minute which is now fixed.

That is the only simple way to do it, that I can think of. Your only other option would be to host a web server that keeps track of the time and have the servers ping it.

I figured it out here is the full solution:

local Lighting = game:GetService("Lighting")
local RunService = game:GetService("RunService")

local MINUTES_IN_A_DAY = 1

local Increment = 24/(MINUTES_IN_A_DAY*60)
local Minute = ((os.time() % 86400)*60)*Increment

RunService.Heartbeat:Connect(function()
    Minute = Minute + Increment
    Lighting:SetMinutesAfterMidnight(Minute)
end)
1 Like

Actually I am having another problem. It isn’t really that big of a deal, but, how would I incorporate deltaTime so it doesn’t go out of sync from server lag?

1 Like

Based on the testimonials on this thread, I wouldn’t trust os.time to be synced across all Roblox servers.

You can make a request to http://google.com and read the date from its headers if you want to get the time consistently.

local HttpService = game:GetService("HttpService")
local response = HttpService:RequestAsync({Url="http://google.com"}) 
print(response.Headers.date) -- Mon, 25 Feb 2019 07:25:12 GMT

EDIT If you can convert this to a unix timestamp, just add the seconds since the response from the request was received (you’ll really only need to make this request once when your server starts) to get time that is synced.

2 Likes

Based on @XAXA’s post, HttpService is a very capable method of tracking time. After a certain amount of time, you can send another HttpRequest to check the time again to be able to sync your game incase of

It shouldn’t go out of sync if I use deltaTime but I can’t seem to get it in properly.

I might switch to this method.

Here’s a module that you can use. It returns time that is synced.

local monthStrMap = {
	Jan=1,
	Feb=2,
	Mar=3,
	Apr=4,
	May=5,
	Jun=6,
	Jul=7,
	Aug=8,
	Sep=9,
	Oct=10,
	Nov=11,
	Dec=12
}
local HttpService = game:GetService("HttpService")
local function RFC2616DateStringToUnixTimestamp(dateStr)
	local day, monthStr, year, hour, min, sec = dateStr:match(".*, (.*) (.*) (.*) (.*):(.*):(.*) .*")
	local month = monthStrMap[monthStr]
	local date = {
		day=day,
		month=month,
		year=year,
		hour=hour,
		min=min,
		sec=sec
	}
	
	return os.time(date)
end

local isInited = false
local originTime = nil
local responseTime = nil
local responseDelay = nil
local function inited()
	return isInited
end

local function init()
	if not isInited then
		local ok = pcall(function()
			local requestTime = tick()
			local response = HttpService:RequestAsync({Url="http://google.com"}) 
			local dateStr = response.Headers.date
			originTime = RFC2616DateStringToUnixTimestamp(dateStr)
			responseTime = tick()
			-- Estimate the response delay due to latency to be half the rtt time
			responseDelay = (responseTime-requestTime)/2
		end)
		if not ok then
			warn("Cannot get time from google.com. Make sure that http requests are enabled!")
			originTime = os.time()
			responseTime = tick()
			responseDelay = 0
		end
		
		isInited = true
	end
end

local function time()
	if not isInited then
		init()
	end
	
	return originTime + tick()-responseTime - responseDelay
end

return {
	inited=inited,
	init=init,
	time=time
}

Paste it in a module (name it syncedtime I guess) and require it:

local syncedtime = require(workspace.syncedtime)
syncedtime.init() -- Will make the request to google.com if it hasn't already.

print(syncedtime.time()) -- prints something like 1551081813.3696.

Since this isn’t an integer, you can use it in your loop and the result wouldn’t be choppy.

local Lighting = game:GetService("Lighting")
local RunService = game:GetService("RunService")
local syncedtime = require(workspace.syncedtime)
syncedtime.init() -- Will make the request to google.com if it hasn't already.

-- I would just convert this to seconds since it's easier to work with.
local SECONDS_IN_A_DAY = 1*60

-- It's redundant to define a scale since we already have SECONDS_IN_A_DAY
-- local scale = 4

RunService.Heartbeat:Connect(function()
	local t = syncedtime.time()
	-- percentInCurrentDay goes from 0 to 1, 0 begin 00:00:00 and
	-- 1 being 24:00:00
	local percentInCurrentDay = t%SECONDS_IN_A_DAY / SECONDS_IN_A_DAY
	-- Lighting.ClockTime can be decimal, and ranges from [0-24).
	-- Use this rather than Lighting:SetMinutesAfterMidnight()
	Lighting.ClockTime = percentInCurrentDay*24
end)
18 Likes