如何在 Garmin 设备中处理 timestamp_16?

how to handle timestamp_16 in Garmin devices?

我拥有一台 Garmin Vivosport,用于跟踪我的活动和睡眠,我想 运行 对我通过 Garmin Connect 下载的 FIT 文件中的心率数据进行一些分析。

问题是我没能正确对齐时间戳。

有人问了类似的问题here,但我没有找到答案,也无法评论以添加我的问题。

here 所述,在 FIT 文件中,时间戳信息分为两个不同的变量:一个 timestamp 不时出现,一个 timestamp_16 附加到每一个单独的测量。按照他们的说法,timestamp_16包含了实际时间戳的低16位,所以应该和前面的timestamp.

的高16位结合起来

我使用的是 2019 年 5 月 1 日记录的数据。文件涵盖一天的 24 小时,所以第一个数据点在 00:00(我在 Garmin Connect 的图形界面中检查过,一切都匹配) .在这个文件中,我发现这是第一个感兴趣的数据条目:

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

上面截取的第一个 monitoring 对象是在包含心率的对象之前包含 timestamp 的最后一个对象,因此它与 linked 中的内容相匹配说明。

根据这些信息,我尝试了一些解决方案,但其中 none 我设法获得了文件中第一个数据点的实际时间戳,该时间戳为 2019 年 5 月 1 日的 00:00 (也不在几分钟之内)。

如果我按照上述 link 中给出的说明进行操作,我会得到:

mesgTimestamp = timestamp
mesgTimestamp += ( timestamp_16 - ( mesgTimestamp & 0xFFFF ) ) & 0xFFFF

但结果是:2019-05-01 12:49:00

我也尝试用timestamp_16手动替换timestamp的低16位,但还是没有成功:

timestamp    :   0b1011100110010001011111001011000
timestamp_16 :                   0b111100110011100
result       :   0b1011100110010000111100110011100

上面result对应的datetime值为datetime.datetime(2019, 4, 30, 18, 36, 44).

Here 是我所有尝试的代码。 Here 是一个正在讨论的 github 问题。

正如你在上面看到的,我无法得到正确的结果,即 2019 年 5 月 1 日 00:00。除此之外,如果我在位级别手动应用 Garmin 的配方,与我应用他们给出的公式得到的结果相比,我得到的结果不同。

此外,我得到的结果与非零分秒的时间相差很大,这让我相信这不是时区问题(我也尝试过但没有成功) .

有没有人找到一个稳定的解决方案?如果你有的话,能否请你分享一些东西(也有其他语言的,我对这里的逻辑感兴趣)?

几个月来我一直在努力把这件事做好(在我的业余时间做这件事),但这种缺乏结果真的令人沮丧:\

考虑到特殊的 Garmin 纪元,它比 Unix 时间戳纪元晚了 631065600 秒,计算需要在那个特殊的时间进行(如果只是一个正常的偏移量就不会这样,但是这些偏移量不是严格相加的,因此时间的 "absolute value" 很重要)。只需减去 631065600:

dt_offset = datetime.datetime(2019,4,30,22,0,0,0)
timestamp = int(datetime.datetime.timestamp(dt_offset)) - 631065600
timestamp_16 = 31132

以任何合理的方式应用时间增量,例如:

mesgTimestamp = timestamp
mesgTimestamp += ( timestamp_16 - ( mesgTimestamp & 0xFFFF ) ) & 0xFFFF

或者:

mesgTimestamp = timestamp + ((timestamp_16 - timestamp) & 0xffff)

或者:

mesgTimestamp = (timestamp & 0xffff0000) | timestamp_16
if mesgTimestamp < timestamp:
  mesgTimestamp += 0x10000

使用生成的时间戳时再次应用 Garmin 纪元偏移量:

print('New:', datetime.datetime.fromtimestamp(mesgTimestamp + 631065600, pytz.timezone('Europe/Zurich')))

结果:New: 2019-05-01 00:01:00+02:00够接近了吗?