models/classes/runner/navigation/QtiRunnerNavigation.php
public static function checkTimedSectionExit(RunnerServiceContext $context, $nextPosition)
    {
        $timerConfig = $context->getTestConfig()->getConfigValue('timer');
        if (empty($timerConfig['keepUpToTimeout'])) {
            /* @var AssessmentTestSession $session */
            $session = $context->getTestSession();
            $route = $session->getRoute();
            $section = $session->getCurrentAssessmentSection();
            $limits = $section->getTimeLimits();

            // As we have only one identifier for the whole adaptive section it will consider a jump of section on the first item
            if(!($context instanceof QtiRunnerServiceContext) || !$context->isAdaptive() ){
                $isJumpOutOfSection = false;
                if (($nextPosition >= 0) && ($nextPosition < $route->count())) {
                    $nextSection = $route->getRouteItemAt($nextPosition);

                    $isJumpOutOfSection = ($section->getIdentifier() !== $nextSection->getAssessmentSection()->getIdentifier());
                }

                if ($isJumpOutOfSection && $limits != null && $limits->hasMaxTime()) {
                    $assessmentItemRefs = $section->getComponentsByClassName('assessmentItemRef');
                    foreach ($assessmentItemRefs as $assessmentItemRef) {
                        $itemSessions = $session->getAssessmentItemSessions($assessmentItemRef->getIdentifier());

                        if($itemSessions !== false){
                            foreach ($itemSessions as $itemSession) {
                                $itemSession->endItemSession();
                            }
                        }
                    }
                }

            }
        }
    }
public static function checkTimedSectionExit(RunnerServiceContext $context, $nextPosition)
    {
        $timerConfig = $context->getTestConfig()->getConfigValue('timer');
        if (empty($timerConfig['keepUpToTimeout'])) {
            /* @var AssessmentTestSession $session */
            $session = $context->getTestSession();
            $route = $session->getRoute();
            $section = $session->getCurrentAssessmentSection();
            $limits = $section->getTimeLimits();

            // As we have only one identifier for the whole adaptive section it will consider a jump of section on the first item
            if(!($context instanceof QtiRunnerServiceContext) || !$context->isAdaptive() ){
                $isJumpOutOfSection = false;
                if (($nextPosition >= 0) && ($nextPosition < $route->count())) {
                    $nextSection = $route->getRouteItemAt($nextPosition);

                    $isJumpOutOfSection = ($section->getIdentifier() !== $nextSection->getAssessmentSection()->getIdentifier());
                }

                if ($isJumpOutOfSection && $limits != null && $limits->hasMaxTime()) {
                    $assessmentItemRefs = $section->getComponentsByClassName('assessmentItemRef');
                    foreach ($assessmentItemRefs as $assessmentItemRef) {
                        $itemSessions = $session->getAssessmentItemSessions($assessmentItemRef->getIdentifier());

                        if($itemSessions !== false){
                            foreach ($itemSessions as $itemSession) {
                                $itemSession->endItemSession();
                            }
                        }
                    }
                }

            }
        }
    }
Check if a timed section is exited
@param RunnerServiceContext $context
@param int $nextPosition