Maybe with a bit of php. The logout is key, so only the log in immediately before the log out will be used - and of course it needs to be in userid + time order.
Then I would use a flexi table to display the results - but you would need to do a bit more work for that with paging.
I'm also using get_recordset_sql() rather than get_records() because potentially there will be a lot of records.
$sql = "SELECT l.userid,
l.time AS timeaction,
CASE WHEN l.action = 'login' THEN l.time ELSE 0 END AS timestart,
CASE WHEN l.action = 'logout' THEN l.time ELSE 0 END AS timeend
FROM {log} l
WHERE l.module = 'user'
AND l.action IN ('login', 'logout')
ORDER BY l.userid, l.time";
$logs = $DB->get_recordset_sql($sql);
$sessions = array();
if ($logs->valid()) {
$userid = 0;
$timestart = 0;
$timeend = 0;
foreach ($logs as $log) {
if (!empty($log->timestart)) {
// Logged in.
$userid = $log->userid;
$timestart = $log->timestart;
} else if (!empty($log->timeend)) {
// Logged out.
$session = new stdClass();
$session->userid = $userid;
$session->timestart = $timestart;
$session->timeend = $log->timeend;
$sessions[] = $session;
}
}
$logs->close(); // Required for recordset.
// Use a flexitable to display the results properly with paging.
foreach ($sessions as $session) {
echo 'Userid : ' . $session->userid .
' Time start ' . gmdate("Y-m-d H:i:s", $session->timestart) .
' Time end ' . gmdate("Y-m-d H:i:s", $session->timeend) .
' Duration ' . gmdate("H:i:s", $session->timeend - $session->timestart) . '<br/>';
}
}