How to calculate time

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Cyber-Kun

So I basically want to get the current time of the os save it in a file so that it can be accessed again in a few hours even if the application was not running. then later when I get the new date and time I want to calculate the elapsed time
I know how to get the current time using the Time class but I don’t know if it would be best in a dictionary or string or how I would calculate it

:bust_in_silhouette: Reply From: jgodfrey

Take a look at a previous response here:

https://forum.godotengine.org/147267/how-compare-time-when-leaved-last-time-game-with-current-time

thank you reading through it now

Cyber-Kun | 2023-03-06 20:23

thank you and while that will definitely help I am working with a loadshedding application
and I get the time at wich the power will go out from an api .json downlaoded file
i then will probably do a

var file = "c:/path/to/your/file.json"
var json_as_text = FileAccess.get_file_as_string(file)
var json_as_dict = JSON.parse_string(json_as_text)

then I can access it as a dictionary. and I havent tested it yet but if I then get a new date and time dictionary I assume I can then just subtract the old ones keys from the new ones and get the amount of time between current time and the time the power goes out?

Cyber-Kun | 2023-03-06 20:41

I guess it depends on the form of the time data you get in the JSON. Likely, you can easily take that data and convert it to a Unix epoch format - as outlined in the linked post. The advantage there is that it’s just a single INT value, which makes calculating delta time between any two such values trivial. You just subtract one from the other to get elapsed seconds.

That’s much easier than trying to juggle different time elements (months, days, hours, seconds, …) to properly calculate a delta time.

If you can specify the contents of your JSON, I might be able to offer further suggestions on a potential path forward…

jgodfrey | 2023-03-06 20:49

I will comment to you the json data tomorrow because at this moment I’m struggling to get the menu button node to work. I’va added it to the scene and added elements to it in the inspector as I’m using godot 4. but nothing happens when I click on the button

Cyber-Kun | 2023-03-06 20:52

question!!! would it not be easier to use:

FileAccess.get_modified_time to check the last time the file was updated or would simply reading the file also change the modified time?

Cyber-Kun | 2023-03-06 20:58

Reading the file should not change its modified time. Though, if the actual time value you want is INSIDE the file, I’d much prefer to use that rather than to trust the file’s modified time - since something else COULD change the file’s modified time unexpectedly.

jgodfrey | 2023-03-06 22:39

yeah your right about that but the date isn’t in the file when downloaded if needed I could just concatenate it to the end? of the file in a key called “date”: date2
in wich case I would replace date2 with the the unix epoch format you specified earlier and just compare the current unix epoch format with the one in the file and if current >= than one in file I could just emit signal to download the file again and replace the current one then once again concatenate the current unix epoch time to the new file?

Cyber-Kun | 2023-03-07 11:19

Maybe I misunderstood the situation. I thought the JSON file in question already contained the time value you were interested in. If that’s not the case, and you really do just need to know the creation / modified time of the file itself then, by all means, just use that.

It should already be in Unix epoch time format (IIRC) anyway, so it’ll be easy to use it in the manner I previously suggested.

jgodfrey | 2023-03-07 17:58

when i said

and if current >= than one in file

I meant i would check if the difference between them is more than 24 hours. I just want to redownload the file once a day to make sure it’s up to date with the current information

Cyber-Kun | 2023-03-08 17:43

aslo sorry but this is a totally unrelated question to the subject at hand:
how would I go about creating a new file in godot four under the “user://” directory.

I tried:

var firstLaunchFile =    FileAccess.open(Global.path["FirstTimeLaunch"],FileAccess.READ_WRITE)
FileAccess.WRITE.
firstLaunchFile.store_string(Time.get_datetime_string_from_system())
firstLaunchFile.close()

The reason I am asking is because I just realized the application I’m making would require a bit of a first time launch setup and if it detects that it is the first time the application is running on a new device it should also download regardless of the time in the current file because that file won’t yet exist

so I’m planning to check if it’s the first time the application is running by creating a file.
but first I’ll check if that file exists in user://Firsttimelaunch.txt
and if it doesn’t assume it’s the first time setup for the application download the data and then the application can run from the dates on those json files

but I also think this would be rather complicated just for a first time setup is there maybe a more efficient way to do it?

Cyber-Kun | 2023-03-08 17:50

I assume ANY TIME your file is missing, you need to download it, right? If so, then the first time launch scenario you describe is just a standard case of “file is missing, download it”. So, there’s probably no reason to specifically recognize a “first time launch” scenario, unless there’s more to it than I understand.

jgodfrey | 2023-03-08 18:10

man I’m gonna start thinking I’m dumb. wich I probably am but I would also have to check for some other files I would have to download

Cyber-Kun | 2023-03-08 18:57

but regardless even if I could do it like that I am testing out the engine’s capabilities And in the future I might need to do a more complicated first time launch then anyway and since I’m a total noob I’m using this opertunity to learn as much as possible. while this might result in unnecessary code I could Always clean it up later or just redo it with the bare minimum needed for the application to run responsively

Cyber-Kun | 2023-03-08 19:00

now I’m trying to set a first time launch setting in a config file that way if the application misbehaves for some reason the end user could just go and set the Flaunch to true in the config.cfg. I have a template for config.cfg saved in the res:// but how can I copy that file from res://config.cfg to user://config.cfg and then read the values from that? i assume I would acces it as a variable instance. e.g:

if Flaunch = true:
var defaul_config = FileAccess.open()

or something like that but I have no Idea how I would actually copy or move the file

Cyber-Kun | 2023-03-08 19:07

or maybe do a var file = FileAccess.get_file_as_string("res://defaultconfig.cfg and then var config = ConfigFile.new("user://config.cfg") config.set_value("Flaunch",Flaunch", bool) config.save("user://config.cfg")
but after that I still have no idea how to actually read the files contents to run comparisons with it

Cyber-Kun | 2023-03-08 19:13

where i said config.set_value("Flaunch",Flaunch", bool) I meant config.set_value(file)
so it would essentially read the default config and save it’s contents in a variable then write that variable to the new config file in user://config.cfg

Cyber-Kun | 2023-03-08 19:16

but i’m hoping theres some copy file function that I don’t know about

Cyber-Kun | 2023-03-08 19:17

There is a file copy function.

DirAccess — Godot Engine (stable) documentation in English

jgodfrey | 2023-03-08 19:22

Based on your comments, it seems that the user level config file could just be the first time start indicator. If it doesn’t exist, assume first time and copy/create it. If a user needs to reset, they could just remove the file, which would trigger the first time scenario again.

jgodfrey | 2023-03-08 19:27

I looked at the documentation you linked And I’m not sure how to call that function
would I do something like FileAccess.copy(“res://defaultconfig.cfg”, “user://config.cfg”)?
is the copy function part of the FileAccess class?

Cyber-Kun | 2023-03-08 19:31

is the copy function part of the FileAccess class?

No, it’s part of the DirAccess class (scroll to the top of the linked page for the class info).

Technically, there are 2 file copy functions. One is a static function (copy_absolute()) and one is an instance function (copy()).

For the static function, you can call it like:

DirAccess.copy_absolute("abs_path_to_org_file", "abs_path_to_copied_file")

Note that for this function (as documented), the two paths much be absolute.

For the instance function, you can call it like:

var inst = DirAccess.new()
inst.copy("path_to_org_file", "path_to_copied_file")

Note, for this function (as documented), the two paths can be absolute or relative.

jgodfrey | 2023-03-08 19:39

ok thanks that will help alot also I’m just wondering if inst in your previous comment stands for instance?

Cyber-Kun | 2023-03-08 19:45

and also if I do var inst = DirAccess.new() inst.copy("path_to_org_file", "path_to_copied_file")
will save the filename differantly depending on the copied file path? or will the filename stay the same as the original?

Cyber-Kun | 2023-03-08 19:47

nevermind i figured out the copy part

Cyber-Kun | 2023-03-08 19:50

Thank you so much for your help feels like your a pro helping out a complete idiot

Cyber-Kun | 2023-03-08 19:51

ok thanks that will help alot also I’m just wondering if inst in your previous comment stands for instance?

Either function will work fine, especially if you have absolute paths.

… or will the filename stay the same as the original?

Both methods require that the filename is part of the path info you provide. So, if you specify the same filename in both paths, it’ll keep the same name. If you provide a different “to” file name, it’ll be copied and (effectively) renamed as part of the operation.

jgodfrey | 2023-03-08 19:52

Thank you so much for your help feels like your a pro helping out a complete idiot

No worries - happy to help. :slight_smile:

jgodfrey | 2023-03-08 19:54

ok now that I have copied the file I want to change it’s contents to reflect Flaunched = false

the file looks like this when first copied:

[Flaunch]
Flaunch = true

I open the file by doing var userconfig = FileAccess.open("user://config.cfg")

and I just want to change Flaunch to Flaunch = false
I would have assumed the file could be changed the same way a dictionary could
but I seem to be wrong about that do I just clear the file contents and write them in again?

Cyber-Kun | 2023-03-08 20:10

Certainly, that’s easily done, but before that - did you notice this comment above?

Based on your comments, it seems that the user level config file could just be the first time start indicator. If it doesn’t exist, assume first time and copy/create it. If a user needs to reset, they could just remove the file, which would trigger the first time scenario again.

That’s simpler that what you’re doing now, but maybe it doesn’t support your longer-term goals…

jgodfrey | 2023-03-08 20:15

Also related, the contents of your file looks very much like a classic Windows INI file format. If that’s the case, Godot has an entire class to manage such files. See here:

ConfigFile — Godot Engine (latest) documentation in English

jgodfrey | 2023-03-08 20:17

yeah it definitely would be easier but Like I said I’m using this oppertunity to learn more about godot’s gdscript and how to make use of what they have provided. unfortunately I have found the documentation very difficult to read and understand and being able to look at examples makes it much easier for me to connect the dots so to say

Cyber-Kun | 2023-03-08 20:18

ooh thank you that’s exactly what it is in godot it’s defined with a .cfg but their exactly the same as far as I know in fact when I was researching them a bit I read that godot’s ConfigFile class uses window’s ini files to store things like data and settings. I’ll be reading through the link you just posted

Cyber-Kun | 2023-03-08 20:20

ok thank you I fot it to set the new values with

var config = ConfigFile.new()
		config.set_value("Flaunch", "Flaunch", false)
		config.save(Global.path["config"])

Cyber-Kun | 2023-03-08 20:41

ok now to get back to the Json file I just want to clarify. yes the Json file does contain dates and times ich I am very interested in as tha is the core reason for this application however the file does not contain the time at wich it was last downloaded

Cyber-Kun | 2023-03-08 21:08

however the file does not contain the time at wich it was last downloaded

In that case, it would seem appropriate to use a mix of methods here then. Load the date/time info of interest from the JSON as well as get the file’s modified time to represent the last download time.

It’s not clear to me how many date/time items you’re dealing or what you’re doing with them. If one or more need to be compared for some delta time difference, I’d strongly recommend that you get them all into the same format to ease any necessary calculations.

If you have separate, specific questions - I’d recommend that you open a new question as it’ll better serve future community members looking for similar answers…

jgodfrey | 2023-03-08 21:20

I probably will make a new question if I continue to struggle but I think I got the gist of it

and while I’m not sure how many date/time items has it’s not that many and in this particular file I’m not really interested in those items. I’m more interested in other data this file contains namely the Stage item wich tells me (and the application) wich loadshedding stage we’re in and I can consequently use that information to get a schedule of when the electricity will go out and when it will be on
this schedule will also change from city-city, suburb to suburb, and municipality - municipality. here is the file I’m currently working with however tomorrow I should start working with other files that I will also get from the api:

{“status”:{“capetown”:{“name”:“Cape Town”,“next_stages”:[{“stage”:“3”,“stage_start_timestamp”:“2023-03-09T05:00:00+02:00”},{“stage”:“4”,“stage_start_timestamp”:“2023-03-09T22:00:00+02:00”},{“stage”:“3”,“stage_start_timestamp”:“2023-03-10T05:00:00+02:00”},{“stage”:“4”,“stage_start_timestamp”:“2023-03-10T22:00:00+02:00”},{“stage”:“3”,“stage_start_timestamp”:“2023-03-11T05:00:00+02:00”},{“stage”:“4”,“stage_start_timestamp”:“2023-03-11T22:00:00+02:00”}],“stage”:“4”,“stage_updated”:“2023-03-08T22:00:00.095474+02:00”},“eskom”:{“name”:“Eskom”,“next_stages”:,“stage”:“4”,“stage_updated”:“2023-03-08T05:00:00.182280+02:00”}}}

in this file I’m currently only interested in the “status”:“eskom”: “stage” wich in this particular file would be “4”
but in this file future stages are also listed wich I will start working with at a later date to even further decrease the need to update it so frequently and saving my limited amount of requests to the api wich is only 50 a day meaning I can only update the information of the application once every half an hour

Cyber-Kun | 2023-03-08 21:52

also I would once again like to thank you very much to everything and every dumb question you have answered in helping me with this project. I am planning to probably make a youtube video explaining hopefully everything I’ve learned from this post to help other people who are new to godot just like me and since most other tutorials went out of date since the release of Godot 4
anyway my power is once again gonna go off for the night so I bid you farewell and if I do make that youtube video I’ll give you a shoutout for all your help

Cyber-Kun | 2023-03-08 21:55

hello once again
I am trying to now edit the saved json file after it is downloaded on the first launch and saved to user://stage.json

I tried doing:

var file = FileAccess.open("user://stage.json, FileAccess.READ_WRITE)
var json_dict = JSON.parse_String(file)
print(json_dict)

but it gieves me the following error:

Invalid type in static function ‘parse_string’ in type ‘JSON’. Cannot convert argument 1 from Object to String.

and when I tried:

	var file = FileAccess.open(Global.path["stagefile"], FileAccess.READ_WRITE)
	var json_text = file.get_file_as_string(Global.path["stagefile"])
	var json_dict = JSON.parse_string(json_text)
	print("JSon: \n",json_dict)
	file.close()

when it gets to the print function and prints json_dict it just says null

Cyber-Kun | 2023-03-09 10:36

I’m assuming in the second instance in my above comment it prints null because for some reason the file contents are not being saved to json_dict?
would I just do like previously when you said:

var file = "c:/path/to/your/file.json" var json_as_text = FileAccess.get_file_as_string(file) var json_as_dict = JSON.parse_string(json_as_text) if json_as_dict: print(json_as_dict)

in: How to calculate time - Archive - Godot Forum

then do:

json_as_dict.newkey[Time.get_unix_time_from_system()]

Cyber-Kun | 2023-03-09 10:45

I’ve apparently missed some of the above replies until now. However, I will say that I’m having a hard time following the current state now. It’s all gotten pretty convoluted…

when it gets to the print function and prints json_dict it just says null

The call to JSON.parse_string() will return null if it fails to convert the input arg (json_text in this case) to a Godot data type. So, that’s what’s happened here.

The most likely cause of that is the input (json_text) isn’t valid JSON. What happens if you print that out?

print(json_text)

Does it look like you expect?

jgodfrey | 2023-03-10 18:12

I actually got it working the problem was there wasn’t enough time for the http request node to completely download the file before I tried to modify it so I added some additional checks to make sure it’s done before trying to read or open the file

Cyber-Kun | 2023-03-11 11:37