Garmin: Fix timestamp16 rollover

This commit is contained in:
José Rebelo
2026-02-08 23:24:03 +01:00
committed by José Rebelo
parent 14aadfe0a0
commit 0b124a0f06
4 changed files with 31 additions and 5 deletions
@@ -118,6 +118,7 @@ import nodomain.freeyourgadget.gadgetbridge.util.GB;
public class FitImporter {
private static final Logger LOG = LoggerFactory.getLogger(FitImporter.class);
private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.ROOT);
private final Context context;
private final GBDevice gbDevice;
@@ -156,6 +157,8 @@ public class FitImporter {
* @noinspection StatementWithEmptyBody
*/
public void importFile(final File file) throws IOException, FitParseException {
LOG.debug("Parsing {}", file.getAbsolutePath());
reset();
final FitFile fitFile = FitFile.parseIncoming(file);
@@ -244,8 +247,12 @@ public class FitImporter {
sample.setEndTimestamp(nap.getEndTimestamp() * 1000L);
napSamples.add(sample);
} else if (record instanceof FitMonitoring monitoringRecord) {
LOG.trace("Monitoring at {}: {}", ts, record);
final Long currentMonitoringTimestamp = monitoringRecord.computeTimestamp(lastMonitoringTimestamp);
LOG.trace(
"Monitoring at {}: {}",
SDF.format(new Date(currentMonitoringTimestamp * 1000L)),
record
);
if (!activitySamplesPerTimestamp.containsKey(currentMonitoringTimestamp)) {
activitySamplesPerTimestamp.put(currentMonitoringTimestamp, new ArrayList<>());
}
@@ -591,7 +598,11 @@ public class FitImporter {
for (final long ts : activitySamplesPerTimestamp.keySet()) {
if (prevTs > 0 && ts - prevTs > 60) {
// Fill gaps between samples
LOG.debug("Filling gap between {} and {}", prevTs, ts);
LOG.debug(
"Filling gap between {} and {}",
SDF.format(new Date(prevTs * 1000L)),
SDF.format(new Date(ts * 1000L))
);
for (int i = prevTs + 60; i < ts; i += 60) {
final GarminActivitySample sample = new GarminActivitySample();
sample.setTimestamp(i);
@@ -358,7 +358,20 @@ public class FitMonitoring extends RecordData {
if (timestamp16 != null && lastMonitoringTimestamp != null) {
final int referenceGarminTs = GarminTimeUtils.unixTimeToGarminTimestamp(lastMonitoringTimestamp.intValue());
return (long) (lastMonitoringTimestamp.intValue() + ((timestamp16 - (referenceGarminTs & 0xffff)) & 0xffff));
int timeDiff = (timestamp16 & 0xFFFF) - (referenceGarminTs & 0xFFFF);
// Handle rollover
if (timeDiff < -32768) {
timeDiff += 65536;
} else if (timeDiff > 32768) {
timeDiff -= 65536;
}
return lastMonitoringTimestamp + timeDiff;
}
if (lastMonitoringTimestamp != null) {
return lastMonitoringTimestamp;
}
return getComputedTimestamp();
@@ -10,7 +10,7 @@ import java.util.Locale;
public class GBToStringBuilder extends ToStringBuilder {
public static final GBToStringStyle STYLE = new GBToStringStyle();
private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.US);
private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.ROOT);
public GBToStringBuilder(final Object object) {
super(object, STYLE);
@@ -5,7 +5,9 @@ import org.junit.Test;
import java.io.File;
public class FitImporterTest {
import nodomain.freeyourgadget.gadgetbridge.test.TestBase;
public class FitImporterTest extends TestBase {
@Test
@Ignore("helper test for development, remove this while debugging")
public void localTest() throws Exception {