Detecting a variable change

Hello!

How can I detect when the changes were made for a variable. I simply just want to do checks every minute once the currentMinute variable has changed.


I did try :GetPropertyChangedSignal but well didn’t work out, I also tried doing the .Changed method, didn’t work either. I did found something similar on DevForum, but sadly those were for values.


Variables I use:

local dt = DateTime.now()
local currentHour = dt:FormatLocalTime("HH", "en-us")
local currentMinute = dt:FormatLocalTime("mm", "en-us")

Script I tried to use:

currentMinute.Changed:Connect(function()
	print(currentMinute)
end)

Thank you!

What is currentMinute? If you’re using .Changed and :GetPropertyChangedSignal on it, then it must be an instance. What class of instance? If it’s a ValueBase like NumberValue or IntValue, then the solution is print(currentMinute.Value).

How could I detect its changes even if it’s a variable though? I’ve noticed that the methods I used were for instances.

You can assign the variable value to a Value instance and then detect it

local val = Instance.new("IntValue",workspace)

local timer = 0

task.spawn(function()
	for i = 1,math.huge do
		task.wait(1)
		timer += 1
		val.Value = timer
	end
end)

val.Changed:Connect(function()
	print("Value Changed")
	print(timer)
end)

at this point just use a while true loop

Oh, you want to detect changes on a variable of any type. No, numbers do not have functions or properties, and only instances have change listeners.

I think you’re trying to refresh those currentHour and currentMinute variables all the time so that they are always “up to date.” That’s interesting, because I remember thinking the exact same thing when I was new to programming as well.

Instead of referencing currentMinute whenever you need it, and just expecting that it’s up to date, what you should do is just call the original dt::FormatLocalTime function whenever you need to get the current minute.

1 Like

@aliaun125 No, don’t assign the variable value to a Value instance. That’s an ineffective method of sharing/tracking data - especially for values that can’t be stored in a value instance (ex: a table)

@TwoMadDev No, don’t use a while true loop. There’s no reason to constantly check this and that’s bad practice. If your delay on the loop is negligible, it won’t be good for performance; and conversely if the delay is somewhat significant then it will lose precision.

@ OP

I’d recommend using a Signal module (take your pick, I’d personally recommend GitHub - stravant/goodsignal: A Roblox Lua Signal implementation that has full API and behavioral parity with Roblox' RBXScriptSignal).

Create some type of simple Signal, ex:

local TimeChanged = Signal.new()

Fire the signal whenever the event you want to track happens (ex: whenever you change the value, in your case)

Then, get the Signal to whatever script (or part of the script) where you want the change to be noticed, and then just connect to it like any other event (ex:)

TimeChanged:Connect(function()
     print("Time changed")
end)

If you’re unfamiliar with Signals, here’s an example application for a day and night cycle that includes a signal whenever the time changes

Example
--// Note: this is untested, so it might not work in production, but the concepts are accurate

local Lighting = game:GetService("Lighting")
local SignalModule = require(Path.To.Signal.Module)

local AmountOfMinutesToAdd = 5
local DelayTime = 1

local TimeChanged = Signal.new()

--// Day Night cycle
task.spawn(function()
	while true do
		task.wait(DelayTime)
		
		Lighting:SetMinutesAfterMidnight(Lighting:GetMinutesAfterMidnight() + AmountOfMinutesToAdd)
		
		TimeChanged:Fire(Lighting.ClockTime) --// As an example, you can fire whatever arguments you want here
	end
end)

--// Detect changes
TimeChanged:Connect(function(NewTime)
     print("Time has changed to", NewTime)
end)
2 Likes

Really appreciate it, but how would I implement this in my case, I want to detect when the minute changes in live. I’ve already got the DateTime.now() times ready, I just need to detect the changes, how would I implement that?
Update:


task.spawn(function()
	while true do
		task.wait()
		minute = dt:FormatLocalTime("mm", "en-us")
		hour = dt:FormatLocalTime("HH", "en-us")
		sig:Fire(minute, hour)
	end
end)

sig:Connect(function(newMinute, newHour)
	print("Time has changed to", newHour,":",newMinute)
end)

I basically got this, it did start printing “Time has changed to {hour} : {minute}”, but what went wrong was that it didn’t update the time, and also it just spammed non-stop the same print message with the same time, but why?

Ohhh, I see what you’re trying to do.

There are no events associated with the system’s minute or hour changing, so an approximation of this can be done by doing constant checks to see if it changes between each loop.

function hourChanged(newHour)
	print("Hour is now", newHour)
end

function minuteChanged(newMinute)
	print("Minute is now", newMinute)
end

function checkTimeEveryFrame()
	local currentHour, currentMinute = getCurrentHourAndMinute()
	if currentHour ~= LastHour then
		task.spawn(hourChanged, currentHour)
		LastHour = currentHour
	end
	if currentMinute ~= LastMinute then
		task.spawn(minuteChanged, currentMinute)
		LastMinute = currentMinute
	end
end

function getCurrentHourAndMinute()
	local dt = DateTime.now()
	return dt:FormatLocalTime("HH", "en-us"), dt:FormatLocalTime("mm", "en-us")
end

LastHour, LastMinute = getCurrentHourAndMinute()
game:GetService("RunService").Stepped:Connect(checkTimeEveryFrame)

Ideally you would have a single TimeChanged and not have some of the ugly copy-pasted code you see here, but this works fine for just hours and minutes.

1 Like

I got a way around that, thank you ALL for helping me, really appreciate y’all! :heart:

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.