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.