frigate/web/src/utils/timelineUtil.tsx
Josh Hawkins 45213d0420
Some checks are pending
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
Miscellaneous fixes (#23082)
* openvino log message and preview directory checks

* restrict config vars for viewer users

* recording timestamp fix

when startTime is exactly on an hour boundary, findIndex returns the first matching chunk, which is the previous hour's chunk (where before == startTime), instead of the correct chunk (where after == startTime)

the bug shows up when using the share timestamp feature and sharing a specific timestamp on the exact hour mark. when accessing the shared link, the timeline would jump to the incorrect hour

* use helper for chunked time range

* Adjustments to contributing docs

* tweak

* Improve wording

* tweak

---------

Co-authored-by: Nicolas Mowen <nickmowen213@gmail.com>
2026-05-01 11:25:26 -06:00

86 lines
2.2 KiB
TypeScript

import { endOfHourOrCurrentTime } from "./dateUtil";
import { TimeRange } from "@/types/timeline";
/**
*
* @param timeRange
* @returns timeRange chunked into individual hours
*/
export function getChunkedTimeDay(timeRange: TimeRange): TimeRange[] {
const endOfThisHour = new Date(timeRange.before * 1000);
endOfThisHour.setSeconds(0, 0);
const data: TimeRange[] = [];
const startDay = new Date(timeRange.after * 1000);
startDay.setUTCMinutes(0, 0, 0);
let start = startDay.getTime() / 1000;
let end = 0;
for (let i = 0; i < 24; i++) {
startDay.setHours(startDay.getHours() + 1);
if (startDay > endOfThisHour) {
break;
}
end = endOfHourOrCurrentTime(startDay.getTime() / 1000);
data.push({
after: start,
before: end,
});
start = startDay.getTime() / 1000;
}
data.push({
after: start,
before: Math.floor(timeRange.before),
});
return data;
}
/**
* Find the chunk index that contains the given timestamp.
* Uses half-open intervals [after, before) for all chunks except the last,
* which uses a closed interval [after, before] so the terminal boundary
* is always reachable.
*/
export function findChunkIndex(chunks: TimeRange[], timestamp: number): number {
return chunks.findIndex((chunk, i) => {
const isLast = i === chunks.length - 1;
return (
chunk.after <= timestamp &&
(isLast ? chunk.before >= timestamp : chunk.before > timestamp)
);
});
}
export function getChunkedTimeRange(
startTimestamp: number,
endTimestamp: number,
) {
const endOfThisHour = new Date();
endOfThisHour.setHours(endOfThisHour.getHours() + 1, 0, 0, 0);
const data: TimeRange[] = [];
const startDay = new Date(startTimestamp * 1000);
startDay.setUTCMinutes(0, 0, 0);
let start = startDay.getTime() / 1000;
let end = 0;
while (end < endTimestamp) {
startDay.setHours(startDay.getHours() + 1);
if (startDay > endOfThisHour) {
break;
}
end = endOfHourOrCurrentTime(startDay.getTime() / 1000);
data.push({
after: start,
before: end,
});
start = startDay.getTime() / 1000;
}
return { start: startTimestamp, end: endTimestamp, ranges: data };
}