Timer every day

Greetings!

before you reply, be completely aware that what i’m looking for is not a daily reward 24h system.

How would I script a timer that displays how long until the end of the UTC day? For example, it’d say “23h, 50m” at 00:10 irl time.

Obviously this should reset to “24h, 0m” when it hits 00:00 the following day

Cheers.

Something like

local tomorrow = os.date("!*t", os.time() + 86400)
local tomorrowSeconds = os.time({
	year = tomorrow.year, month = tomorrow.month, day = tomorrow.day,
	hour = 0, min = 0, sec = 0 
})
local Seconds = tomorrowSeconds - os.time()

local Minutes = math.round(Seconds/60)

local Hours = math.round(Minutes/60)



print("Time Left: "..Hours.."h,"..Minutes.."m")

Could work

1 Like

Works. Just something else, how would you display the seconds? Seems like an amateur question but I’m not quite sure how haha

I believe (correct me if I’m incorrect) but this line here:

local tomorrow = os.date("!*t", os.time() + 86400)

This would get the current time os.time() was called the next time tomorrow (so say this script was called at 18:00UTC/6PM UTC, that would mean the timer would end at 6PM the next day. The OP wanted something that would want to end at midnight the next day.

This implementation does one half of it, but the missing component here is getting the seconds elapsed from the day the countdown is called and the amount left.

Although based on this posts solution (Using OS.Time to make something happen at midnight every day - #5 by CheeseGodTheEpic), I’ve added comments to explain the lines as much as possible.

--[[ We can use os.time, as os.time is current UTC (server time).
The parameter (being a table) can customise what timezone you
want to use too. ]]


-- Create a new function to get our timer back as a string.
function GetNewTimeAsString(seconds)
	
	--[[ An example of modulus (%) is the remainder of the right number
	going into the left number, example is: 10 % 3, which returns 1, since
	counting up in 3's, 3, 6, 9. It can't count up anymore otherwise
	the number would exceed 10, so 1 is left over. ]]
	
	--[[ Example for this is, say the seconds was 300 (5 minutes).
	(300 - (300 % 60) / 60 ). (300 % 60) == 0. So now it becomes:
	(300 - 0) / 60. 300 - 0 is 300. Now it's:
	300 / 60, which is 5. :) ]]
	local minutes = (seconds - seconds % 60) / 60
	
	--[[ And now we can shift our seconds in accordance to our just-calculated
	minutes. Example again: seconds = 300 - 5 * 60.
	BIDMAS rules apply, multiplication goes first. 5 * 60 is 300.
	300 - 300. Which is 0, because we know the seconds goes into 5 minutes
	from above without any seconds left over! ]]
	seconds = seconds - minutes * 60
	
	--[[ The exact same rules apply here as what has been demonstrated above.
	This time we're just dealing with a different component of the time.
	And minutes now becomes the seconds in these calculations. ]]
	local hours = (minutes - minutes % 60) / 60
	minutes = minutes - hours * 60
	
	-- And here, we can return our formatted string.
	return hours .. "h " .. minutes .. "m " .. seconds .. "s"
end

-- Create a coroutine so code can run below this point.
--[[ Another reason to do so is we can remove/stop the functionality
once the countdown is done. ]]
local timerCountdown = coroutine.create(function()
	
	--[[ This will repeat every 0.5 second and print GetNewTimeAsString(). 
    I've changed this to 0.5 as the delay of 1 second moves the time to the next day,
    so there's never an opportunity for the countdown to stop. ]]

	while task.wait(0.5) do
		local currentTime = os.time()
		local currentDate = os.date("!*t", currentTime)
		
		local secondsElapsedInDay = currentDate["hour"] * 3600 + currentDate["min"] * 60 + currentDate["sec"]
		local secondsLeftInDay = 86400 - secondsElapsedInDay

		--[[ If the amount of seconds of the day 
		minus the current seconds left is 0, then we know that
		the end of the day has been reached. :) ]]
		if secondsLeftInDay == 0 then
			--[[ So here, we can stop our task by breaking the loop.
            Not before we print out 0h 0m 0s manually! :) ]]
            print("0h 0m 0s")
			break
		end

        --[[ Print the new time. This however will be in a GUI label
		at some point. ]]
		print(GetNewTimeAsString(secondsLeftInDay))
	end
end)

--[[ Resume/start our coroutine here. If you want the coroutine to close/be removed,
then you can use coroutine.close(timerCountdown) to remove it from memory essentially.
Just because we break the loop doesn't mean the coroutine still isn't stored in
memory somewhere. :) ]]
coroutine.resume(timerCountdown)

I hope it helps you. :slight_smile:

1 Like

Incredible detail. I have definitely learned something from this.

@CodeSaviour Your solution also worked, but wasn’t exactly what I was looking for :sweat_smile:
Thanks both :smile:

2 Likes

Unsure what you meant there, but it works. somehow

image
image

1 Like

In your implementation, you did os.time() + 86400.

os.time() is always UTC (as the server time is UTC, it will be different on your local machine, try it. :grin:).

Lets say in this instance, os.time() had a time value of 18:24:32. Assuming we could do arithmetic between a time and an integer, doing 18:24:32 + 86400 will still return 18:24:32 but the day will be the next day, as we’re just adding a day to the current os.time() in seconds.

Hope that makes sense, because sometimes I read back on things I’ve written and it doesn’t make sense. Makes sense in my head… :upside_down_face:

EDIT: My bad, I’m thinking of os.date, not os.time. Silly me.

Still, for anyone reading this in the future, os.date is different on the server compared to your local machine because of different timezones. So never assume that the servers os.date is the same as the clients os.date.

My apologies @GameManCZ_GMC.

2 Likes

@TheLocalBritishDev I’ve changed the script, I’ve encountered an edge case where the timer continues/never stops at 0, since the time in seconds in the day resets, as it’s the next day so it never truly reaches 0. I’ve changed the while wait(1) to while wait(0.5) to have a gap in time to realise the next day is approaching, so the condition is able to be broken out of.

1 Like