0 votes

Hi everyone,

my timer works, displaying minutes and seconds.

func _process(_delta):

    if second >59:
        minute += 1
        second = 0

    if minute >59:
        hour += 1
        minute = 0

    set_text(str(hour) + ":" + str(minute) + ":" + str(second))

Instead of e. g. 15:9 I'd like 15:09, so I add

if second <10:
    second = "0" + str(second)

But then it throws the error

Invalid operands 'String' and 'int' in operator '>'.

for the first line in the function.

The weird thing is that it works flawlessly in a timer displaying the actual time (date_time = OS.get_datetime()), so I wonder why it won't work in this case.
Any ideas?

Godot version 3.2.3
in Engine by (365 points)

2 Answers

+1 vote
Best answer

There's no need to reinvent the wheel here, because regular string output formatting in C (and GDScript!) already provides a mechanism for leading zeroes.

When using string formatting, you can use the placeholder %d to signify an integer number. Formatting/inserting the number 5 with this will result in… 5. This is not exactly what we want.

If you provide a minimum length, you'll end up with a padded number: Formatting/inserting 5 using %2dwill get you  5. This is close, but still not perfect.

Finally, we can add a leading zero to signify that we actually want to pad with zeroes rather than spaces: Formatting/inserting 5 using %02d will get us 05. This is exactly what we want! And even better, if you pass in 10 you'll get 10!

The rest works pretty much the way you did:

# Demo variable, 1 hour (3600 seconds), 2 minutes (120 seconds), and 3 seconds
var time = 3723 # 3600 + 120 + 3

var seconds = time % 60
time /= 60
var minutes = time % 60
time /= 60
var hours = time

# Here's all the magic happening
print("%02d:%02d:%02d" % [hours, minutes, seconds])
# Output: 01:02:03
by (224 points)
selected by

wow this is cool, I didn't know this!

Thanks for explaining all this. I tried something similar like

text = "%d:%02d" % [floor($Timer.time_left / 60), int($Timer.time_left) % 60]

func _on_Timer_timeout():
    countdown_time -= 1

which counts down the wait_time of the TimerNode (only that I won't succeed in adding hours here...).
So I wonder, for a countdown, where would I have to put time_left into your approach?

Since time__left is the remaining time in seconds, you can just do something like var time = int($timer.time_left) in my approach.

That's it, works like a charm, thank you so much.

One last thought: it appears to print on each frame. How would I have it only printing once each second?

There are tons of possible solutions to this, you could probably just save the calculated seconds and see if they change between calls.

+1 vote

in gdscript a variable can be int and string too
so if you say second = "0" + str(second) it will become a string ("08" e.g.)
and the problem is that at the next _process it will try to, well you can read the error
so you can't "08">59
there would be many ways to fix this, I'd propose to create a variable like this

var str_second = str(second)
if second <10:
    str_second = "0" + str_second

and use str_second for set_text

another approach:
I actually needed to do the same for my project, my code looks like this:

var minutes: int = current_sec / 60
var seconds: float = current_sec - minutes * 60
var opt_zero: String = "0" if seconds < 10 else ""
draw_string(font, current_pixel + Vector2(3, 20), "%s:%s%s" % [minutes, opt_zero, seconds])
by (288 points)

This is it, thank you!

(sudomono on Reddit suggests String padzeros ( int digits ), which indeed works great as well.)

May I add a following question? A counter starting from 0 is one thing, but I can't figure out how to build a countdown until a set time in the future. Say it's 16:30 and I enter a time in a Label, 18:45, the timer should count down 02:15:00. (Or some time until the next day if I enter 09:00 o'clock...)
I assume a way would be to calculate the difference between "now" and the entered time and then have the timer counting down the result. But can a timer Node do that?

EDIT:

Yes, I've been trying around with something like %s:%s%s" % [hours, minutes, seconds] as well, especially to add some bbcode, but I have a bit of a hard time with these yet...
Your suggestion is very straight though, and thanks for the explanation why my code didn't work!

quickly looking at the documentation I don't see a way to reverse how the Timer node is run
so probably you need to program that logic
it doesn't seem that hard though
you probably need to convert everything to seconds (that seems like an easy way to do it)
so convert the current time and the set time to seconds, and subtract them from each other
e.g. 2:15:00 = 8100 s will be the difference
then you can do something similar like I did with current_sec to get the hour and minute back
edit: you can also use % if you have 2 integers (but it won't work with floats) e.g. 135 % 60 will be 15, and also 135 / 60 will be whole 2 (not 2.25 or something, only if you use a float for one input)
yeah I also mostly use + to add string variables together, this was an exception that I looked that up, how to use it :D
yoo yeah that pad_zeros is the intended way probably

So many ways to skin a cat... I've never stumbled over these pad_zeros before and I wonder how much more there is that would be oh so helpful.

Breaking everything down to seconds seems reasonable. And then probably deal with up to 24:00 hours and the remaining time from 00:00 separately, add them together and ticker them off. Sounds so easy ; D

Ride on, thanks again!

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.