mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-21 06:59:09 +00:00
fix: delays account for midnight
This commit is contained in:
@@ -506,6 +506,7 @@ describe('getCurrent()', () => {
|
|||||||
timeStart: 79200000, // 22:00:00
|
timeStart: 79200000, // 22:00:00
|
||||||
timeEnd: 600000, // 00:10:00
|
timeEnd: 600000, // 00:10:00
|
||||||
countToEnd: true,
|
countToEnd: true,
|
||||||
|
dayOffset: 0,
|
||||||
},
|
},
|
||||||
clock: 79500000, // 22:05:00
|
clock: 79500000, // 22:05:00
|
||||||
timer: {
|
timer: {
|
||||||
@@ -516,6 +517,7 @@ describe('getCurrent()', () => {
|
|||||||
rundown: {
|
rundown: {
|
||||||
actualStart: 79200000,
|
actualStart: 79200000,
|
||||||
plannedEnd: 600000,
|
plannedEnd: 600000,
|
||||||
|
currentDay: 0,
|
||||||
},
|
},
|
||||||
_timer: {
|
_timer: {
|
||||||
pausedAt: null,
|
pausedAt: null,
|
||||||
@@ -527,6 +529,35 @@ describe('getCurrent()', () => {
|
|||||||
expect(current).toBe(dayInMs - 79500000 + 600000);
|
expect(current).toBe(dayInMs - 79500000 + 600000);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('handles overnight count-to-end after midnight', () => {
|
||||||
|
const state = {
|
||||||
|
eventNow: {
|
||||||
|
timeStart: 23 * MILLIS_PER_HOUR, // 23:00:00
|
||||||
|
timeEnd: 1 * MILLIS_PER_HOUR, // 01:00:00
|
||||||
|
countToEnd: true,
|
||||||
|
dayOffset: 0,
|
||||||
|
},
|
||||||
|
clock: 30 * MILLIS_PER_MINUTE, // 00:30:00 on day 1
|
||||||
|
timer: {
|
||||||
|
addedTime: 0,
|
||||||
|
duration: Infinity,
|
||||||
|
startedAt: 23 * MILLIS_PER_HOUR,
|
||||||
|
},
|
||||||
|
rundown: {
|
||||||
|
actualStart: 23 * MILLIS_PER_HOUR,
|
||||||
|
plannedEnd: 1 * MILLIS_PER_HOUR,
|
||||||
|
currentDay: 1,
|
||||||
|
},
|
||||||
|
_timer: {
|
||||||
|
pausedAt: null,
|
||||||
|
hasFinished: false,
|
||||||
|
},
|
||||||
|
} as RuntimeState;
|
||||||
|
|
||||||
|
const current = getCurrent(state);
|
||||||
|
expect(current).toBe(30 * MILLIS_PER_MINUTE);
|
||||||
|
});
|
||||||
|
|
||||||
it('handles events that were started late', () => {
|
it('handles events that were started late', () => {
|
||||||
const state = {
|
const state = {
|
||||||
clock: 82000000, // 22:46:40 <--- starting 16 min after the scheduled end
|
clock: 82000000, // 22:46:40 <--- starting 16 min after the scheduled end
|
||||||
|
|||||||
@@ -77,9 +77,11 @@ export function getCurrent(state: RuntimeState): number {
|
|||||||
|
|
||||||
if (countToEnd) {
|
if (countToEnd) {
|
||||||
// count to end runs to its fixed end, so added time does not stretch the countdown
|
// count to end runs to its fixed end, so added time does not stretch the countdown
|
||||||
const isEventOverMidnight = timeStart > timeEnd;
|
const dayOffset = state.eventNow.dayOffset ?? 0;
|
||||||
const correctDay = isEventOverMidnight ? dayInMs : 0;
|
const currentDay =
|
||||||
return correctDay - clock + timeEnd;
|
state.rundown.currentDay ?? (timeStart > timeEnd && clock <= timeEnd ? dayOffset + 1 : dayOffset);
|
||||||
|
const endDay = timeStart > timeEnd ? dayOffset + 1 : dayOffset;
|
||||||
|
return timeEnd + endDay * dayInMs - (clock + currentDay * dayInMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (startedAt === null) {
|
if (startedAt === null) {
|
||||||
|
|||||||
@@ -99,6 +99,36 @@ describe('getExpectedStart()', () => {
|
|||||||
expect(getExpectedStart(testEvent, { ...testState, isLinkedToLoaded: false })).toBe(110); // <-- when gap is not enough to compensate for the running behind it absorbs at much as possible
|
expect(getExpectedStart(testEvent, { ...testState, isLinkedToLoaded: false })).toBe(110); // <-- when gap is not enough to compensate for the running behind it absorbs at much as possible
|
||||||
// expect(getExpectedStart(testEvent, { ...testState, isLinkedToLoaded: true })).toBe(70); This should not be possible
|
// expect(getExpectedStart(testEvent, { ...testState, isLinkedToLoaded: true })).toBe(70); This should not be possible
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('negative delay cannot move a day 0 event before the rundown start', () => {
|
||||||
|
const testState = {
|
||||||
|
currentDay: 0,
|
||||||
|
totalGap: 0,
|
||||||
|
offset: 0,
|
||||||
|
mode: OffsetMode.Absolute,
|
||||||
|
actualStart: null,
|
||||||
|
plannedStart: null,
|
||||||
|
isLinkedToLoaded: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(getExpectedStart({ timeStart: 0, delay: -5, dayOffset: 0 as Day }, testState)).toBe(0);
|
||||||
|
expect(getExpectedStart({ timeStart: 10, delay: -5, dayOffset: 0 as Day }, testState)).toBe(5);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('negative delay can move a later-day event back to the previous day', () => {
|
||||||
|
const testState = {
|
||||||
|
currentDay: 0,
|
||||||
|
totalGap: 0,
|
||||||
|
offset: 0,
|
||||||
|
mode: OffsetMode.Absolute,
|
||||||
|
actualStart: null,
|
||||||
|
plannedStart: null,
|
||||||
|
isLinkedToLoaded: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(getExpectedStart({ timeStart: 0, delay: -5, dayOffset: 1 as Day }, testState)).toBe(dayInMs - 5);
|
||||||
|
expect(getExpectedStart({ timeStart: 10, delay: -20, dayOffset: 1 as Day }, testState)).toBe(dayInMs - 10);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Relative offset mode', () => {
|
describe('Relative offset mode', () => {
|
||||||
@@ -413,6 +443,19 @@ describe('getExpectedEnd()', () => {
|
|||||||
expect(getExpectedEnd({ ...testEvent, dayOffset: 0 as Day }, { ...baseState, currentDay: 0, offset: 0 })).toBe(150);
|
expect(getExpectedEnd({ ...testEvent, dayOffset: 0 as Day }, { ...baseState, currentDay: 0, offset: 0 })).toBe(150);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('a countToEnd event with negative delay can start on the previous day but keeps its fixed end', () => {
|
||||||
|
const testEvent = {
|
||||||
|
timeStart: 0,
|
||||||
|
duration: 50,
|
||||||
|
delay: -10,
|
||||||
|
dayOffset: 1 as Day,
|
||||||
|
countToEnd: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(getExpectedStart(testEvent, { ...baseState, currentDay: 0, offset: 0 })).toBe(dayInMs - 10);
|
||||||
|
expect(getExpectedEnd(testEvent, { ...baseState, currentDay: 0, offset: 0 })).toBe(dayInMs + 50);
|
||||||
|
});
|
||||||
|
|
||||||
test('a countToEnd event is anchored to its wall-clock end in relative mode', () => {
|
test('a countToEnd event is anchored to its wall-clock end in relative mode', () => {
|
||||||
const testEvent = {
|
const testEvent = {
|
||||||
timeStart: 100,
|
timeStart: 100,
|
||||||
|
|||||||
@@ -23,13 +23,8 @@ export function getExpectedStart(
|
|||||||
const { timeStart, dayOffset, delay } = event;
|
const { timeStart, dayOffset, delay } = event;
|
||||||
const { currentDay, totalGap, isLinkedToLoaded, offset, mode, actualStart, plannedStart } = state;
|
const { currentDay, totalGap, isLinkedToLoaded, offset, mode, actualStart, plannedStart } = state;
|
||||||
|
|
||||||
//How many days from the currently running event to this one
|
const absoluteDelayedStart = Math.max(0, dayOffset * dayInMs + timeStart + delay);
|
||||||
const relativeDayOffset = dayOffset - currentDay;
|
const normalisedTimeStart = absoluteDelayedStart - currentDay * dayInMs;
|
||||||
|
|
||||||
const delayedStart = Math.max(0, timeStart + delay);
|
|
||||||
|
|
||||||
//The normalised start time of this event relative to the currently running event
|
|
||||||
const normalisedTimeStart = delayedStart + relativeDayOffset * dayInMs;
|
|
||||||
|
|
||||||
let relativeStartOffset = 0;
|
let relativeStartOffset = 0;
|
||||||
|
|
||||||
@@ -69,9 +64,7 @@ export function getExpectedEnd(
|
|||||||
* - the end time is always the wall clock
|
* - the end time is always the wall clock
|
||||||
*/
|
*/
|
||||||
if (event.countToEnd) {
|
if (event.countToEnd) {
|
||||||
// account for day offset
|
const plannedEnd = event.dayOffset * dayInMs + event.timeStart + event.duration - state.currentDay * dayInMs;
|
||||||
const relativeDayOffset = event.dayOffset - state.currentDay;
|
|
||||||
const plannedEnd = event.timeStart + event.duration + relativeDayOffset * dayInMs;
|
|
||||||
|
|
||||||
// count to end should finish on the planned time or on start
|
// count to end should finish on the planned time or on start
|
||||||
return Math.max(expectedStart, plannedEnd);
|
return Math.max(expectedStart, plannedEnd);
|
||||||
|
|||||||
Reference in New Issue
Block a user