0

I am trying to manage some mods for a game, and to do that I'm trying to decode the metadata file that comes with every mod, called meta.cpp https://community.bistudio.com/wiki/Arma_3_meta.cpp

/// Version of meta.cpp content
protocol = 1;
/// Steam Workshop item id
publishedid = 123456790;
/// Steam Workshop item name
name = "Splendid mod";
/// Time of last update of the Steam Workshop Item (in Unix time format)
timestamp = 9876432101234567890;
/// Mod hash that is send by the server to the client instead of calculated hash)
hashOverride = 1234567890;

now, the wiki states that the timestamp is in "unix time format" but i've never seen a 19 digit timestamp before, i know that,

for example, this date here: 5248381691709134656

converts into: 11 Aug, 2018 @ 7:55am

however, using a "unix time in nanoseconds" to date time converter, I get:

Wednesday, 25 April 2136 03:48:11.709

how can I, in python, get the correct datetime from that 19 digit timestamp?

Update, full code here:

import os, sys
from struct import pack, unpack
from datetime import datetime

dir = "C:/Users/Hobnob/Desktop/a"


def sick_timestamp_to_datetime(ts):
    double_value, = unpack("d", ts.to_bytes((ts.bit_length() + 7) // 8, "big"))
    return datetime.utcfromtimestamp(double_value * 1000000)

def datetime_to_sick_timestamp(dt):
    double_value = dt.timestamp() / 1000000
    return int.from_bytes(pack("d", double_value), "big")

def getMods(path):
    mods = []
    folders = os.listdir(path)
    for folder in folders:
        if folder[0] == "@":
            f = open(dir + "/" + folder + "/" + "meta.cpp","r")
            lines = f.readlines()
            f.close()
            mod = {}
            mod["folder"] = folder
            for line in lines:
                l = line.replace(";\n","").split(" = ")
                mod[l[0]] = l[1]
            mods.append(mod)
    return mods

mods = getMods(dir)

for mod in mods:

    print(mod["name"])
    timestamp = int(mod["timestamp"])
    print(timestamp)
    print(sick_timestamp_to_datetime(int(mod["timestamp"])))

Returns

"501st Map Pack v2"

5248711435420930091

1970-01-01 00:00:00

"A2 Declassified: Fireteam Zulu"

5248689294479321327

timestamp out of range for platform time_t
Stack trace:
 >  File "C:\Users\Hobnob\source\repos\modupdater\modupdater\modupdater.py", line 10, in sick_timestamp_to_datetime
 >    return datetime.utcfromtimestamp(double_value * 1000000)
 >  File "C:\Users\Hobnob\source\repos\modupdater\modupdater\modupdater.py", line 45, in <module>
 >    print(sick_timestamp_to_datetime(int(mod["timestamp"])))
Loaded '__main__'

https://pastebin.com/PM6GM0bL here is the full list of timestamps

"501st Map Pack v2"
5248711435420930091
"A2 Declassified: Fireteam Zulu"
5248689294479321327
"ace"
5248567866178789836
"ACE Extension - Attachment Switching"
5248293196869838307
"ACE Interaction Menu Expansion"
5248353067687941306
"ACE 3 Extension (Animations and Actions)"
5248367057664748391
"ACEX"
5248567868005486912
"Achilles"
5248652679121433871
"ADV - ACE Medical"
5248556573318018227
"Advanced Urban Rappelling"
5247735201687266573
"Advanced Rappelling"
5247762938166464462
"Advanced Sling Loading"
5247774176389108621
"BackpackOnChest"
5247950803847045667
"Bariga"
5248103043689999886
"CBA_A3"
5248723145042436614
"Chernarus Redux"
5248701460962875112
"cTab"
5248593656826007018
"CUP Terrains - Core"
5248586602008770300
"CUP Terrains - CWA"
5248586583814180413
"CUP Terrains - Maps"
5248586587369758004
"CZ75  Ambient Music"
5248101810620391503
"Enhanced Movement"
5248301739023854775
"Fletcher's Section 3 Declassified"
5248426533389705768
"Full Halo Music Pack"
5248581288006497593
"GRAD Trenches"
5248704472075201653
"HEV Patch"
5248670178536489949
"@HossSFX"
5248185113942384632
"Ihantala Winter"
5248630560826935325
"Lesh's Towing Mod"
5248599604131388953
"Madrigal Terrain - Operation Trebuchet"
5248733653744790207
"MCC Sandbox 4 -  Mission Making The Easy Way"
5248645695274158809
"OPCAN 2.0 by LM mods"
5248401400168196805
"Operation: Arsenal Expansion for OPTRE"
5248730766708129383
"Operation: TREBUCHET"
5248603069875536903
"Operation: TREBUCHET ACE Compat"
5248376212550867197
"Operation: TREBUCHET First Contact"
5248473794045345616
"OPTRE Plus - Operation Trebuchet+"
5248647342224736589
"Pulau"
5248569532565546274
"Remove stamina - ACE 3"
5248391666542436225
"Remove stamina"
5247824615698862513
"Ruha"
5248715949612612608
"Saint Kapaulio"
5248656593080042266
"ShackTac User Interface"
5248685384579272109
"SpecWar Gru 7 Official Mod Pack"
5248708196766508739
"@SurvivableCrashes"
5248194876544700239
"Tactical Weapon Swap"
5248560002828336128
"task_force_radio"
5248649840653578614
"TF Dust Storm Menu"
5248127215316370816
"TF Snow Storm Menu"
5248265470088709854
"USS Nimitz"
5248381691709134656
"Vana - Loadout Management (Alpha)"
5248229446545023209
"Vcom AI V3.3.3"
5248675353813691382
"VT5 - Valtatie 5 | Final Release | Finnish terrain for A3"
5247792698550562340
"@xCam_Taunus"
5247879225408317229
"Zombies and Demons"
5248001900987810777
Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
Hobnob11
  • 80
  • 13
  • 2
    It's not valid unix timestamp. – Olvin Roght Oct 15 '19 at 16:26
  • But even the wiki page on the meta file has a 19 digit timestamp, every single mod has the same size of timestamp as well... – Hobnob11 Oct 15 '19 at 16:28
  • @Hobnob11 The wiki example you're referring to is clearly just an example: `9876432101234567890` (notice the digits go from 9 down to 0 and then back up to 9 and another 0) – rdas Oct 15 '19 at 16:30
  • The value in your question can only be any time in the coming future if it's in nanoseconds. Even then, it's about 166 years. If you count from 1970 (unix time 0) that ends up in 2136. – rdas Oct 15 '19 at 16:32
  • It's `double`, you need to unpack it as double. – Olvin Roght Oct 15 '19 at 16:32
  • The example I gave, 5248381691709134656, is from a real meta file, and I know the date it converts too, because in the mods download page it lists the last updated date. – Hobnob11 Oct 15 '19 at 16:33
  • @OlvinRoght how would i do that in python? – Hobnob11 Oct 15 '19 at 16:33
  • @Hobnob11, are you sure that provided example is valid? Cause I've tested and got `24 Aug, 2018 @ 10:00am`. – Olvin Roght Oct 15 '19 at 16:36
  • I have been using a online converter, I am not sure how to convert the string "5248711435420930091" into a timestamp in python. – Hobnob11 Oct 15 '19 at 16:44
  • @Hobnob11, you've posted that `5248711435420930091` equals `11 Aug, 2018 @ 7:55am`. Is this 100% correct? Cause I've converted it as double and got `24 Aug, 2018 @ 10:00am`. – Olvin Roght Oct 15 '19 at 16:46
  • this is getting a tad confusing, but the timestamp you posted and the timestamp i posted are not the same. this timestamp 5248381691709134656 is, according to the mods download page, 11 Aug, 2018 @ 7:55am, could you please explain how you converted that though because i do not understand how to convert the string to the correct datatype @OlvinRoght – Hobnob11 Oct 15 '19 at 16:52
  • @Hobnob11, `res = unpack("d", num.to_bytes((num.bit_length() + 7) // 8, byteorder="big"))[0] * 1000000`. – Olvin Roght Oct 15 '19 at 16:57
  • @Hobnob11, to double check you can scrape 4-5 examples and compare with result you got. – Olvin Roght Oct 15 '19 at 17:01
  • this function you've posted seems to do the trick, trying to figure out how to take this string representation of the number though – Hobnob11 Oct 15 '19 at 17:04
  • @Hobnob11, what do you mean? Your input is string, not a number? – Olvin Roght Oct 15 '19 at 17:14
  • When i put "num = 5248381691709134656" into your function, i get: 1535104827.878373 when I put num = int(timestamp) I get 7.679197057461664e-93 and then datetime errors with invalid argument – Hobnob11 Oct 15 '19 at 17:18
  • @Hobnob11, I've posted my answer, try to use it. – Olvin Roght Oct 15 '19 at 17:30
  • @OlvinRoght okay so I've added my source code, I get [Errno 22] Invalid argument from the last line... and the debugger shows the number to be 7.679197057461664e-93, but when i put in a breakpoint and look at the first one which works, i get 1535104827.878373 – Hobnob11 Oct 15 '19 at 17:30
  • @Hobnob11, what does `print(timestamp)` prints? – Olvin Roght Oct 15 '19 at 17:33
  • @OlvinRoght I have edited my answer to show the output, it doesn't appear to work for every ID, and breaks on the second one. https://pastebin.com/PM6GM0bL here is the full list of timestamps – Hobnob11 Oct 15 '19 at 17:48
  • @Hobnob11, what a coincidence. Then my answer is not correct and I don't know what is this timestamp – Olvin Roght Oct 15 '19 at 17:55
  • @Hobnob11, it could be timestamp, but with different epoch.. – Olvin Roght Oct 15 '19 at 18:27

1 Answers1

2

This weird timestamp is double value of unix timestamp read as int. You can use next functions for convertion:

from struct import pack, unpack
from datetime import datetime, timezone

def sick_timestamp_to_datetime(ts):
    double_value, = unpack("d", ts.to_bytes((ts.bit_length() + 7) // 8, "big"))
    return datetime.fromtimestamp(double_value * 1000000, timezone.utc)

def datetime_to_sick_timestamp(dt):
    double_value = dt.timestamp() / 1000000
    return int.from_bytes(pack("d", double_value), "big")
Olvin Roght
  • 7,677
  • 2
  • 16
  • 35