Skip to content

Commit 317d1ac

Browse files
brontideclaude
andcommitted
Fix motion activity endpoint returning invalid timestamps after pandas 3.0 upgrade
pandas 3.0 changed DatetimeIndex internal storage from datetime64[ns] (nanoseconds) to datetime64[us] (microseconds). The motion activity endpoint in review.py converted DatetimeIndex to epoch seconds using: df.index = df.index.astype(int) // (10**9) This assumed nanosecond resolution, dividing by 10^9 to get seconds. With microsecond resolution the division produces values ~1000x too small (e.g. 1774785 instead of 1774785600), causing every entry to have a start_time near zero. The frontend timeline could not match these timestamps to the visible range, so motion indicator bars disappeared entirely — despite the underlying recording data being correct. Replace the resolution-dependent integer division with pandas Timedelta arithmetic: df.index = (df.index - _EPOCH) // _ONE_SECOND This is resolution-independent (produces correct results on datetime64[s], [ms], [us], and [ns]), ~148x faster than the per-element .timestamp() alternative, produces native Python int types that serialize cleanly to JSON, and is backwards-compatible with older pandas versions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 148e11a commit 317d1ac

File tree

1 file changed

+6
-1
lines changed

1 file changed

+6
-1
lines changed

frigate/api/review.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@
4040

4141
logger = logging.getLogger(__name__)
4242

43+
# Pre-computed constants for resolution-independent datetime-to-epoch conversion
44+
# (pandas 3.0+ stores datetime64 as microseconds, not nanoseconds)
45+
_EPOCH = pd.Timestamp("1970-01-01")
46+
_ONE_SECOND = pd.Timedelta("1s")
47+
4348
router = APIRouter(tags=[Tags.review])
4449

4550

@@ -659,7 +664,7 @@ def motion_activity(
659664
df.iloc[i : i + chunk, 0] = 0.0
660665

661666
# change types for output
662-
df.index = df.index.astype(int) // (10**9)
667+
df.index = (df.index - _EPOCH) // _ONE_SECOND
663668
normalized = df.reset_index().to_dict("records")
664669
return JSONResponse(content=normalized)
665670

0 commit comments

Comments
 (0)