I own a Garmin Vivosport which I use to track my activities and my sleep, and I want to run some analysis on my own heart rate data taken from the FIT files I download via Garmin Connect.
The problem is that I do not manage to align timestamps properly.
A similar question is asked here but I didn't find an answer, nor could comment to add my question.
As explained here, in the FIT files the timestamp information is split into two different variables: a timestamp
which appears every now and then, and a timestamp_16
which is attached to every individual measurement. According to what they say, timestamp_16
contains the lower 16 bits of the actual timestamp, so it should be combined with the higher 16 bits of the previous timestamp
.
I am using data recorded on May 1st 2019. Files cover the 24h of the day, so the first data point is at 00:00 (I checked this in the graphic interface of Garmin Connect and things match). In this file I find this to be the first data entry of interest:
monitoring
* activity_type: sedentary
* current_activity_type_intensity: (8,)
* intensity: 0
* timestamp: 2019-04-30 22:00:00
[some other lines in between]
monitoring
* heart_rate: 72
* timestamp_16: 31132
the first monitoring
object in the above snipped si the last one containing a timestamp
before the one containing the heart rate, so it matches what is written in the linked instructions.
With these informations, I tried a few solution but with none of them I managed to get the actual timestamp of the first data point in the file to be at 00:00 on May 1st 2019 (nor within a few minutes).
If I follow the instructions given in the above link, I get:
mesgTimestamp = timestamp
mesgTimestamp += ( timestamp_16 - ( mesgTimestamp & 0xFFFF ) ) & 0xFFFF
but the outcome is: 2019-05-01 12:49:00
I also tried to replace by hand the lower 16 bits of timestamp
with timestamp_16
, but again no success:
timestamp : 0b1011100110010001011111001011000
timestamp_16 : 0b111100110011100
result : 0b1011100110010000111100110011100
The datetime
value corresponding to the above result
is datetime.datetime(2019, 4, 30, 18, 36, 44)
.
Here is the code with all my attempts. Here is a github issue where this is being discussed.
As you can see above I cannot get the right result, i.e. May 1st 2019 00:00. In addition to this, if I apply Garmin's recipe by hand at the bit level I get a different result compared to what I get applying the formula they give.
Also, the results that I get are off by an amount of time having non zero minutes and seconds, and this makes me believe that this is not a timezone issue (I also tried to play with it with no success).
Has anyone found a stable solution to this? Could you please share something, if you have it (also in other languages, I am interested in the logic here)?
I am trying to get this right since a few months (working on this during my spare time), but this lack of result is really depressing :\
Take the special Garmin epoch into account, it's 631065600 seconds later than the Unix timestamp epoch, the calculations need to happen in that special time (if it was just a normal offset that wouldn't be the case, but these offsets are not strictly additive so the "absolute value" of the time matters). Just subtract 631065600:
dt_offset = datetime.datetime(2019,4,30,22,0,0,0)
timestamp = int(datetime.datetime.timestamp(dt_offset)) - 631065600
timestamp_16 = 31132
Apply the time delta in any reasonable way, for example:
mesgTimestamp = timestamp
mesgTimestamp += ( timestamp_16 - ( mesgTimestamp & 0xFFFF ) ) & 0xFFFF
Or:
mesgTimestamp = timestamp + ((timestamp_16 - timestamp) & 0xffff)
Or:
mesgTimestamp = (timestamp & 0xffff0000) | timestamp_16
if mesgTimestamp < timestamp:
mesgTimestamp += 0x10000
Apply the Garmin epoch-offset again when using the resulting timestamp:
print('New:', datetime.datetime.fromtimestamp(mesgTimestamp + 631065600, pytz.timezone('Europe/Zurich')))
Result: New: 2019-05-01 00:01:00+02:00
Close enough?