Godot Version
4.3
Question
I’m trying to do something which was relatively easy in Javascript and in Lua, and which proves a bit tricky in GDScript and Godot: getting the number of milliseconds elapsed since midnight.
I’ve come up with the following code but since I run it every frame I was wondering if there was a more efficient way to achieve this.
Thanks for your help.
static func ms_since_midnight() -> float:
# Get current time in unix epoch seconds,
# with sub-second precision (hence a float)
var unix_time: float = Time.get_unix_time_from_system()
# Get midnight of current day in unix epoch seconds:
# First get the current system time and date as dict and define midnight.
var now: Dictionary = Time.get_datetime_dict_from_system(false)
var d: Dictionary = {
'year': now.year,
'month': now.month,
'day': now.day,
'hour': 0,
'minute': 0,
'second': 0
}
# Then convert midnight to unix epoch seconds.
# We use cast the returned int to a float,
# in order to keep precision for the "now - midnight" delta later.
var midnight: float = Time.get_unix_time_from_datetime_dict(d)
# Offset by current timezone:
# Multiply bias (in minutes) by 60 to get seconds
midnight = midnight - Time.get_time_zone_from_system().bias * 60
# Return milliseconds elapsed since midnight
return (unix_time - midnight) * 1000
You could cache the midnight value, only have to update it if it’s over 24 hours
1 Like
Indeed I could. Thank you for confirming that there isn’t much else to optimise here, I was hoping it could be cleaner.
What about this version?
static func ms_since_midnight() -> float:
var now: Dictionary = Time.get_datetime_dict_from_system(false)
var midnight: Dictionary = {
'year': now.year,
'month': now.month,
'day': now.day,
'hour': 0,
'minute': 0,
'second': 0
}
var now_unix: float = Time.get_unix_time_from_system()
var midnight_unix: float = Time.get_unix_time_from_datetime_dict(midnight)
var timezone_offset: float = Time.get_time_zone_from_system().bias * 60
return (now_unix - (midnight_unix - timezone_offset)) * 1000
Is that a tiny bit cleaner?
Your version looks great though and no, I can’t see any way to improve on it significantly.
The cache idea from @gertkeno was a good one though. If at the start of your game you log the ms since midnight, const STARTING_MS_SINCE_MIDNIGHT say, could you not just use something like this every frame?
func get_ms_since_midnight() -> int:
return Time.get_ticks_msec() - STARTING_MS_SINCE_MIDNIGHT
Thanks. Still a lot of work for something I thought would be simpler.
I thought about using Time.get_ticks_msec()
, yes, but this is a precise clock-based application and I don’t want to be concerned with drifting or hiccups. Also, it’s supposed to be able to run across midnight and if I do that I’ll have to check each frame if midnight has passed, which would amount to basically the same number of calculations.
1 Like