Summary
_parse_record takes the measurement timestamp from the Eufy record's update_time. That field
reflects when the record was last modified server-side, not when the weigh-in happened. Eufy
appears to rewrite it in bulk on some accounts, which makes --backfill-days file the entire
history under a single date.
Forward syncing is unaffected — for a fresh weigh-in create_time and update_time are a couple
of seconds apart — so this only shows up when backfilling.
Version
eufy-sync 1.8.1 (PyPI), Python 3.12, Linux.
The line
eufy_sync/eufy_client.py:385
update_time = record.get("update_time", record.get("create_time", 0))
The create_time fallback is effectively dead code: update_time is always present in the
/device/data response, so dict.get's default never fires.
Evidence
On my account, /device/data returns 548 records:
| Field |
Distinct values |
Range |
create_time |
544 |
2021-03-04 → 2026-08-02 |
update_time |
116 |
2021-03-04 → 2026-08-02 |
The update_time values are heavily clustered: 318 of the 319 records for my profile share a
single ~2½-minute window on 2026-07-05. I don't know what triggered it server-side — an app
migration or a re-link of the scale would be my guess — but the effect is that
--backfill-days 3650 proposed 318 measurements all stamped that one afternoon:
[DRY RUN] Would sync to garmin: 92.6 kg at 2026-07-05 19:02:30+00:00
[DRY RUN] Would sync to garmin: 93.3 kg at 2026-07-05 19:02:30+00:00
[DRY RUN] Would sync to garmin: 96.4 kg at 2026-07-05 19:02:30+00:00
...
[DRY RUN] Would sync 319 measurements to Garmin.
create_time on those same records is spread naturally across five years, which matches my
actual weigh-in history.
Steps to reproduce
Reproducing needs an account whose records have been bulk-touched, so the general check is:
- Fetch the raw records (
EufyClient._get_records(None)).
- Compare
len({r["create_time"] for r in recs}) against
len({r["update_time"] for r in recs}).
- If the
update_time set is much smaller, --dry-run --backfill-days 3650 will show the
collapsed dates.
Impact
Anyone backfilling on an affected account writes their whole history to Garmin Connect under one
date. Bulk-deleting body composition entries from Garmin Connect is painful, so this is
unpleasant to recover from — worth catching before it lands.
Because it only manifests on backfill, an affected user can easily not notice until the data is
already in Garmin.
Suggested fix
Prefer create_time, keep update_time as the fallback:
update_time = record.get("create_time") or record.get("update_time", 0)
I've been running this locally as a build-time patch and the resulting backfill dates line up with
my real history.
A cheap safety net worth considering alongside it: have --dry-run/backfill warn when a large
number of measurements share one timestamp, since that's a strong signal the date field is wrong
rather than the data being genuinely that dense.
Happy to open a PR if the one-liner is the direction you'd want.
Summary
_parse_recordtakes the measurement timestamp from the Eufy record'supdate_time. That fieldreflects when the record was last modified server-side, not when the weigh-in happened. Eufy
appears to rewrite it in bulk on some accounts, which makes
--backfill-daysfile the entirehistory under a single date.
Forward syncing is unaffected — for a fresh weigh-in
create_timeandupdate_timeare a coupleof seconds apart — so this only shows up when backfilling.
Version
eufy-sync 1.8.1 (PyPI), Python 3.12, Linux.
The line
eufy_sync/eufy_client.py:385The
create_timefallback is effectively dead code:update_timeis always present in the/device/dataresponse, sodict.get's default never fires.Evidence
On my account,
/device/datareturns 548 records:create_timeupdate_timeThe
update_timevalues are heavily clustered: 318 of the 319 records for my profile share asingle ~2½-minute window on 2026-07-05. I don't know what triggered it server-side — an app
migration or a re-link of the scale would be my guess — but the effect is that
--backfill-days 3650proposed 318 measurements all stamped that one afternoon:create_timeon those same records is spread naturally across five years, which matches myactual weigh-in history.
Steps to reproduce
Reproducing needs an account whose records have been bulk-touched, so the general check is:
EufyClient._get_records(None)).len({r["create_time"] for r in recs})againstlen({r["update_time"] for r in recs}).update_timeset is much smaller,--dry-run --backfill-days 3650will show thecollapsed dates.
Impact
Anyone backfilling on an affected account writes their whole history to Garmin Connect under one
date. Bulk-deleting body composition entries from Garmin Connect is painful, so this is
unpleasant to recover from — worth catching before it lands.
Because it only manifests on backfill, an affected user can easily not notice until the data is
already in Garmin.
Suggested fix
Prefer
create_time, keepupdate_timeas the fallback:I've been running this locally as a build-time patch and the resulting backfill dates line up with
my real history.
A cheap safety net worth considering alongside it: have
--dry-run/backfill warn when a largenumber of measurements share one timestamp, since that's a strong signal the date field is wrong
rather than the data being genuinely that dense.
Happy to open a PR if the one-liner is the direction you'd want.