O Moodle armazena grande parte das datas no banco de dados como Unix timestamp, ou seja, um número inteiro que representa a quantidade de segundos transcorridos desde 1º de janeiro de 1970. Para exibir essas informações em relatórios SQL, é necessário converter o valor para um formato de data e hora legível.
Neste tutorial, você aprenderá como formatar datas do Moodle, tratar valores zerados, filtrar registros por período e calcular intervalos de tempo usando consultas SQL no MySQL ou MariaDB.
Como as datas são armazenadas no Moodle
Nas tabelas do Moodle, é comum encontrar campos como:
timecreated: data de criação do registro;timemodified: data da última alteração;lastaccess: data do último acesso;firstaccess: data do primeiro acesso;timestart: data inicial;timeend: data final;timecompleted: data de conclusão;timefinish: data de finalização;timesubmitted: data de envio de uma atividade.
Esses campos normalmente armazenam valores semelhantes ao seguinte:
1752865200
Esse número precisa ser convertido para uma data antes de ser apresentado em um relatório.
Formatar datas do Moodle com FROM_UNIXTIME
No MySQL e no MariaDB, a função FROM_UNIXTIME() converte um Unix timestamp para um valor de data e hora.
A consulta abaixo retorna a data e a hora do último acesso do usuário com o ID 2:
SELECT
id,
firstname,
lastname,
FROM_UNIXTIME(lastaccess, '%d/%m/%Y %H:%i:%s') AS ultimo_acesso
FROM mdl_user
WHERE id = 2;
O resultado será semelhante a:
2 | Administrador | Moodle | 18/07/2026 14:35:20
Os caracteres utilizados na formatação representam:
%d: dia com dois dígitos;%m: mês com dois dígitos;%Y: ano com quatro dígitos;%H: hora no formato de 24 horas;%i: minutos;%s: segundos.
Para relatórios brasileiros, um dos formatos mais utilizados é:
%d/%m/%Y %H:%i:%s
Erro comum ao utilizar FROM_UNIXTIME no WHERE
A função FROM_UNIXTIME() não deve ser utilizada isoladamente dentro da cláusula WHERE, pois ela apenas converte o valor e não cria uma condição de comparação.
A consulta abaixo está incorreta:
SELECT *
FROM mdl_user
WHERE FROM_UNIXTIME(lastaccess, '%d/%m/%Y %H:%i:%s')
AND id = 2;
Além de não comparar a data com nenhum valor, aplicar funções diretamente sobre a coluna dentro do WHERE pode impedir o uso eficiente de índices em consultas maiores.
Para apenas exibir a data formatada, utilize a função no SELECT:
SELECT
id,
username,
firstname,
lastname,
FROM_UNIXTIME(lastaccess, '%d/%m/%Y %H:%i:%s') AS ultimo_acesso
FROM mdl_user
WHERE id = 2;
Tratar datas com valor zero no Moodle
Em várias tabelas do Moodle, o valor 0 indica que determinado evento ainda não aconteceu. Um usuário que nunca acessou a plataforma, por exemplo, pode ter o campo lastaccess igual a zero.
Para evitar que o relatório apresente uma data correspondente ao início da época Unix, utilize uma expressão CASE:
SELECT
id,
firstname,
lastname,
CASE
WHEN lastaccess = 0 THEN 'Nunca acessou'
ELSE FROM_UNIXTIME(lastaccess, '%d/%m/%Y %H:%i:%s')
END AS ultimo_acesso
FROM mdl_user
ORDER BY lastname, firstname;
Também é possível retornar NULL quando a data estiver zerada:
SELECT
id,
firstname,
lastname,
FROM_UNIXTIME(
NULLIF(lastaccess, 0),
'%d/%m/%Y %H:%i:%s'
) AS ultimo_acesso
FROM mdl_user;
A função NULLIF(lastaccess, 0) transforma o valor zero em NULL. Dessa forma, FROM_UNIXTIME() também retorna NULL.
Consultar usuários pelo período do último acesso
Para localizar usuários que acessaram o Moodle depois de uma data específica, converta a data informada para Unix timestamp com a função UNIX_TIMESTAMP().
Usuários que acessaram depois de uma data
SELECT
id,
firstname,
lastname,
email,
FROM_UNIXTIME(lastaccess, '%d/%m/%Y %H:%i:%s') AS ultimo_acesso
FROM mdl_user
WHERE deleted = 0
AND suspended = 0
AND lastaccess >= UNIX_TIMESTAMP('2026-07-01 00:00:00')
ORDER BY lastaccess DESC;
Usuários que acessaram dentro de um período
SELECT
id,
firstname,
lastname,
email,
FROM_UNIXTIME(lastaccess, '%d/%m/%Y %H:%i:%s') AS ultimo_acesso
FROM mdl_user
WHERE deleted = 0
AND lastaccess >= UNIX_TIMESTAMP('2026-07-01 00:00:00')
AND lastaccess < UNIX_TIMESTAMP('2026-08-01 00:00:00')
ORDER BY lastaccess DESC;
O uso de uma data inicial inclusiva e uma data final exclusiva evita problemas com horários, minutos e segundos do último dia do período.
Também é recomendável comparar diretamente o campo numérico com o timestamp. Essa abordagem permite que o banco utilize um índice existente no campo, quando disponível.
Localizar usuários que nunca acessaram o Moodle
Para encontrar contas que nunca registraram acesso, filtre o campo lastaccess pelo valor zero:
SELECT
id,
username,
firstname,
lastname,
email,
FROM_UNIXTIME(timecreated, '%d/%m/%Y %H:%i:%s') AS data_cadastro
FROM mdl_user
WHERE deleted = 0
AND lastaccess = 0
ORDER BY timecreated DESC;
Essa consulta pode ser útil para identificar usuários cadastrados que ainda não entraram no ambiente virtual.
Consultar usuários inativos há determinado número de dias
Para localizar usuários que não acessam o Moodle há mais de 30 dias, compare o campo lastaccess com o timestamp correspondente à data atual menos 30 dias:
SELECT
id,
firstname,
lastname,
email,
FROM_UNIXTIME(lastaccess, '%d/%m/%Y %H:%i:%s') AS ultimo_acesso
FROM mdl_user
WHERE deleted = 0
AND suspended = 0
AND lastaccess > 0
AND lastaccess < UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 30 DAY))
ORDER BY lastaccess ASC;
Para alterar o período, substitua 30 DAY pelo intervalo desejado.
Calcular há quantos dias ocorreu o último acesso
A função TIMESTAMPDIFF() pode ser utilizada para calcular a diferença entre o último acesso e a data atual:
SELECT
id,
firstname,
lastname,
FROM_UNIXTIME(lastaccess, '%d/%m/%Y %H:%i:%s') AS ultimo_acesso,
TIMESTAMPDIFF(
DAY,
FROM_UNIXTIME(lastaccess),
NOW()
) AS dias_sem_acesso
FROM mdl_user
WHERE deleted = 0
AND lastaccess > 0
ORDER BY dias_sem_acesso DESC;
O campo calculado dias_sem_acesso mostra a quantidade de dias transcorridos desde o último acesso do usuário.
Formatar a data de criação do usuário
O campo timecreated da tabela mdl_user registra quando a conta foi criada:
SELECT
id,
username,
firstname,
lastname,
FROM_UNIXTIME(timecreated, '%d/%m/%Y %H:%i:%s') AS data_cadastro
FROM mdl_user
WHERE deleted = 0
ORDER BY timecreated DESC;
Consultar datas de acesso por curso
O campo lastaccess da tabela mdl_user representa o último acesso geral do usuário ao Moodle. Para consultar o último acesso dentro de cada curso, utilize a tabela mdl_user_lastaccess.
SELECT
u.id AS usuario_id,
CONCAT(u.firstname, ' ', u.lastname) AS usuario,
c.id AS curso_id,
c.fullname AS curso,
CASE
WHEN ula.timeaccess = 0 THEN 'Sem acesso registrado'
ELSE FROM_UNIXTIME(ula.timeaccess, '%d/%m/%Y %H:%i:%s')
END AS ultimo_acesso_curso
FROM mdl_user_lastaccess ula
INNER JOIN mdl_user u
ON u.id = ula.userid
INNER JOIN mdl_course c
ON c.id = ula.courseid
WHERE u.deleted = 0
ORDER BY ula.timeaccess DESC;
Consultar datas de matrícula nos cursos
As matrículas dos usuários são registradas na tabela mdl_user_enrolments. O campo timecreated indica quando o vínculo de matrícula foi criado.
SELECT
u.id AS usuario_id,
CONCAT(u.firstname, ' ', u.lastname) AS usuario,
c.id AS curso_id,
c.fullname AS curso,
FROM_UNIXTIME(ue.timecreated, '%d/%m/%Y %H:%i:%s') AS data_matricula,
CASE
WHEN ue.timestart = 0 THEN NULL
ELSE FROM_UNIXTIME(ue.timestart, '%d/%m/%Y %H:%i:%s')
END AS inicio_matricula,
CASE
WHEN ue.timeend = 0 THEN 'Sem data de término'
ELSE FROM_UNIXTIME(ue.timeend, '%d/%m/%Y %H:%i:%s')
END AS fim_matricula
FROM mdl_user_enrolments ue
INNER JOIN mdl_enrol e
ON e.id = ue.enrolid
INNER JOIN mdl_course c
ON c.id = e.courseid
INNER JOIN mdl_user u
ON u.id = ue.userid
WHERE u.deleted = 0
ORDER BY ue.timecreated DESC;
Consultar datas de conclusão de curso
A tabela mdl_course_completions armazena informações relacionadas à conclusão dos cursos. O campo timecompleted contém a data de conclusão, quando o usuário atende aos critérios configurados no curso.
SELECT
u.id AS usuario_id,
CONCAT(u.firstname, ' ', u.lastname) AS usuario,
c.id AS curso_id,
c.fullname AS curso,
CASE
WHEN cc.timecompleted IS NULL OR cc.timecompleted = 0
THEN 'Curso não concluído'
ELSE FROM_UNIXTIME(cc.timecompleted, '%d/%m/%Y %H:%i:%s')
END AS data_conclusao
FROM mdl_course_completions cc
INNER JOIN mdl_user u
ON u.id = cc.userid
INNER JOIN mdl_course c
ON c.id = cc.course
WHERE u.deleted = 0
ORDER BY cc.timecompleted DESC;
Consultar a data de envio de tarefas
Nas versões atuais do Moodle, as tarefas são armazenadas principalmente nas tabelas mdl_assign e mdl_assign_submission.
A consulta abaixo retorna a data de criação e a data da última modificação de cada envio:
SELECT
a.id AS atividade_id,
a.name AS atividade,
c.fullname AS curso,
u.id AS usuario_id,
CONCAT(u.firstname, ' ', u.lastname) AS usuario,
s.status,
FROM_UNIXTIME(s.timecreated, '%d/%m/%Y %H:%i:%s') AS data_criacao_envio,
FROM_UNIXTIME(s.timemodified, '%d/%m/%Y %H:%i:%s') AS ultima_modificacao
FROM mdl_assign_submission s
INNER JOIN mdl_assign a
ON a.id = s.assignment
INNER JOIN mdl_course c
ON c.id = a.course
INNER JOIN mdl_user u
ON u.id = s.userid
WHERE u.deleted = 0
ORDER BY s.timemodified DESC;
Consultar datas das tentativas de questionários
A tabela mdl_quiz_attempts registra as tentativas realizadas nos questionários. Entre os principais campos de data estão timestart, timefinish e timemodified.
SELECT
q.id AS questionario_id,
q.name AS questionario,
c.fullname AS curso,
u.id AS usuario_id,
CONCAT(u.firstname, ' ', u.lastname) AS usuario,
qa.attempt AS tentativa,
qa.state AS situacao,
FROM_UNIXTIME(qa.timestart, '%d/%m/%Y %H:%i:%s') AS inicio,
CASE
WHEN qa.timefinish = 0 THEN 'Tentativa não finalizada'
ELSE FROM_UNIXTIME(qa.timefinish, '%d/%m/%Y %H:%i:%s')
END AS termino
FROM mdl_quiz_attempts qa
INNER JOIN mdl_quiz q
ON q.id = qa.quiz
INNER JOIN mdl_course c
ON c.id = q.course
INNER JOIN mdl_user u
ON u.id = qa.userid
WHERE u.deleted = 0
ORDER BY qa.timestart DESC;
Consultar datas dos registros de log
Nas versões atuais do Moodle, os logs de eventos normalmente são armazenados na tabela mdl_logstore_standard_log. O campo timecreated registra quando o evento aconteceu.
SELECT
l.id,
l.userid,
CONCAT(u.firstname, ' ', u.lastname) AS usuario,
l.eventname,
l.action,
l.target,
l.objecttable,
l.objectid,
l.ip,
FROM_UNIXTIME(l.timecreated, '%d/%m/%Y %H:%i:%s') AS data_evento
FROM mdl_logstore_standard_log l
LEFT JOIN mdl_user u
ON u.id = l.userid
ORDER BY l.timecreated DESC
LIMIT 100;
Para limitar a consulta aos eventos dos últimos sete dias:
SELECT
l.id,
l.userid,
CONCAT(u.firstname, ' ', u.lastname) AS usuario,
l.eventname,
l.action,
l.target,
FROM_UNIXTIME(l.timecreated, '%d/%m/%Y %H:%i:%s') AS data_evento
FROM mdl_logstore_standard_log l
LEFT JOIN mdl_user u
ON u.id = l.userid
WHERE l.timecreated >= UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 7 DAY))
ORDER BY l.timecreated DESC;
Atenção aos nomes das tabelas do Moodle
Alguns nomes de tabelas encontrados em tutoriais antigos não correspondem às tabelas utilizadas nas versões atuais do Moodle.
mdl_user_studentsnão é a tabela padrão para identificar estudantes. Matrículas e funções devem ser consultadas por meio de tabelas comomdl_user_enrolments,mdl_enrol,mdl_role_assignmentsemdl_context.mdl_logpertence ao sistema de logs legado. Em instalações atuais, normalmente é utilizadamdl_logstore_standard_log.mdl_assignementestá escrito incorretamente. A tabela atual da atividade de tarefa émdl_assign.mdl_assignment_submissionspertence ao módulo antigo de tarefas. Nas versões atuais, a tabela normalmente utilizada émdl_assign_submission.mdl_message_readsnão deve ser considerado um nome universal nas versões atuais, pois o subsistema de mensagens passou por alterações entre versões.
Antes de criar um relatório, confirme os nomes e campos disponíveis na versão instalada do Moodle.
O prefixo das tabelas pode ser diferente de mdl_
O prefixo mdl_ é o padrão mais conhecido, mas pode ter sido alterado durante a instalação do Moodle.
O prefixo utilizado pelo ambiente está definido no arquivo config.php:
$CFG->prefix = 'mdl_';
Caso a instalação utilize outro prefixo, adapte as consultas. Por exemplo, uma tabela chamada mdl_user pode estar registrada como moodle_user ou ead_user.
Atenção ao fuso horário
A função FROM_UNIXTIME() utiliza o fuso horário configurado na sessão do MySQL. Portanto, a data apresentada diretamente pelo banco pode ser diferente da data mostrada na interface do Moodle.
Para verificar o fuso horário da sessão e do servidor MySQL, execute:
SELECT
@@session.time_zone AS fuso_sessao,
@@global.time_zone AS fuso_global,
NOW() AS data_atual_mysql;
Quando o Moodle, o PHP e o banco utilizam configurações diferentes de fuso horário, podem ocorrer diferenças de algumas horas nos relatórios.
Não altere o fuso horário global do banco sem avaliar o impacto sobre as outras aplicações que utilizam o mesmo servidor.
Compatibilidade com PostgreSQL
A função FROM_UNIXTIME() é específica do MySQL e do MariaDB. Em uma instalação do Moodle com PostgreSQL, utilize a função TO_TIMESTAMP().
SELECT
id,
firstname,
lastname,
TO_CHAR(
TO_TIMESTAMP(lastaccess),
'DD/MM/YYYY HH24:MI:SS'
) AS ultimo_acesso
FROM mdl_user
WHERE id = 2;
Para filtrar por data no PostgreSQL, utilize EXTRACT(EPOCH FROM ...):
SELECT
id,
firstname,
lastname,
TO_CHAR(
TO_TIMESTAMP(lastaccess),
'DD/MM/YYYY HH24:MI:SS'
) AS ultimo_acesso
FROM mdl_user
WHERE lastaccess >= EXTRACT(
EPOCH FROM TIMESTAMP '2026-07-01 00:00:00'
);
Validação das consultas
Para validar uma consulta que trabalha com datas do Moodle:
- Execute inicialmente a consulta para apenas um usuário ou curso conhecido.
- Compare a data retornada pelo SQL com a informação apresentada na interface do Moodle.
- Verifique se o campo possui valor zero ou
NULL. - Confirme o fuso horário do banco de dados.
- Confira se o prefixo das tabelas é realmente
mdl_. - Antes de executar relatórios grandes, teste a consulta com um
LIMIT.
Um teste simples pode ser realizado com:
SELECT
id,
firstname,
lastname,
lastaccess AS timestamp_original,
FROM_UNIXTIME(lastaccess, '%d/%m/%Y %H:%i:%s') AS data_formatada
FROM mdl_user
WHERE lastaccess > 0
ORDER BY lastaccess DESC
LIMIT 10;
O campo timestamp_original permite comparar o número armazenado com a data convertida.
Problemas comuns ao consultar datas do Moodle
A data retorna 01/01/1970
Esse resultado geralmente ocorre quando o campo contém o valor zero. Utilize CASE ou NULLIF() para tratar registros que ainda não possuem uma data válida.
A data está algumas horas adiantada ou atrasada
Verifique o fuso horário do Moodle, do PHP e da sessão do banco de dados. A função FROM_UNIXTIME() considera o fuso configurado no MySQL.
A consulta não retorna registros no período esperado
Confira se a data utilizada no filtro foi convertida corretamente com UNIX_TIMESTAMP(). Também verifique se o campo possui zero ou NULL.
A consulta está lenta
Evite aplicar FROM_UNIXTIME() diretamente na coluna usada no WHERE. Prefira converter a data de comparação para timestamp:
-- Evite esta condição em tabelas grandes
WHERE DATE(FROM_UNIXTIME(timecreated)) = '2026-07-18';
-- Prefira comparar o valor numérico
WHERE timecreated >= UNIX_TIMESTAMP('2026-07-18 00:00:00')
AND timecreated < UNIX_TIMESTAMP('2026-07-19 00:00:00');
A segunda forma reduz a necessidade de conversão de cada registro e pode aproveitar melhor os índices existentes.
As datas do Moodle normalmente são armazenadas como Unix timestamps. Em bancos MySQL e MariaDB, utilize FROM_UNIXTIME() para exibir as datas e UNIX_TIMESTAMP() para transformar uma data em um valor adequado para filtros.