Posted on: April 08, 2025 07:51 PM
Posted by: Renato
Categories: Laravel
Views: 204
$curso->data_fim = Helpers::formataDatetimeParaBanco($request->data_fim);
- Function do helper
/**
* Recebe datetime em formato br e passa para formato database
* @param String '01/11/2016 14:31' '01/11/2016 14:31:00'
* @return String '2016-11-01 14:31:00'
*/
public static function formataDatetimeParaBanco($date) {
if (($date == null) || ($date == ""))
return null;
$len = strlen($date);
$date = substr($date, 6, 4) . '-' . substr($date, 3, 2) . '-' . substr($date, 0, 2) . ' ' . substr($date, 11);
if ($len == 16)
$date .= ':00';
return $date;
}
- Como acerto esta data para "3024-01-01 23:59:00" ?
O problema está na função formataDatetimeParaBanco que está fazendo um parsing manual da data sem considerar anos com mais de 4 dígitos. Quando você envia "01/01/3024 23:59", a função está pegando os caracteres das posições erradas para o ano.
Vamos corrigir a função para lidar com anos longos:
public static function formataDatetimeParaBanco($date) { if (($date == null) || ($date == "")) return null; // Divide a string em data e hora $parts = explode(' ', $date); $datePart = $parts[0]; $timePart = $parts[1] ?? '00:00'; // Divide a data em dia, mês e ano $dateComponents = explode('/', $datePart); $day = $dateComponents[0]; $month = $dateComponents[1]; $year = $dateComponents[2]; // Formata a hora (adiciona segundos se necessário) if (strlen($timePart) == 5) { $timePart .= ':00'; } return "$year-$month-$day $timePart"; }
Esta nova versão:
-
Primeiro divide a string em partes de data e hora
-
Separa os componentes da data (dia, mês, ano) corretamente
-
Lida com anos de qualquer tamanho (4 dígitos ou mais)
-
Formata a parte do tempo adequadamente
Para o input "01/01/3024 23:59", agora retornará corretamente "3024-01-01 23:59:00".
Uma alternativa ainda mais robusta seria usar a classe DateTime:
public static function formataDatetimeParaBanco($date) { if (empty($date)) { return null; } $datetime = DateTime::createFromFormat('d/m/Y H:i', $date); if ($datetime === false) { $datetime = DateTime::createFromFormat('d/m/Y H:i:s', $date); } return $datetime ? $datetime->format('Y-m-d H:i:s') : null; }
Esta versão com DateTime é mais limpa e menos propensa a erros, mas pode ter problemas com anos muito distantes (dependendo da versão do PHP). Para anos como 3024, deve funcionar sem problemas.
Aqui está a função com as anotações de propriedade (PHPDoc) adequadas, incluindo tipo de parâmetro, tipo de retorno e descrição detalhada:
/** * Converte uma data no formato brasileiro (DD/MM/YYYY HH:MM) para o formato do banco de dados (YYYY-MM-DD HH:MM:SS) * * @param string|null $date Data no formato brasileiro (DD/MM/YYYY HH:MM ou DD/MM/YYYY HH:MM:SS) * ou string vazia. Ex: "01/01/3024 23:59" ou "01/01/2024 23:59:30" * * @return string|null Retorna a data no formato do banco (YYYY-MM-DD HH:MM:SS) ou null se: * - $date for null * - $date for string vazia * - $date estiver em formato inválido * * @example formataDatetimeParaBanco("01/01/3024 23:59") retorna "3024-01-01 23:59:00" * @example formataDatetimeParaBanco("15/12/2023 08:30:45") retorna "2023-12-15 08:30:45" * @example formataDatetimeParaBanco("") retorna null */ public static function formataDatetimeParaBanco(?string $date): ?string { if (empty($date)) { return null; } $datetime = DateTime::createFromFormat('d/m/Y H:i', $date); if ($datetime === false) { $datetime = DateTime::createFromFormat('d/m/Y H:i:s', $date); } return $datetime ? $datetime->format('Y-m-d H:i:s') : null; }
Principais melhorias nas anotações:
-
Adicionado
@param string|nullindicando que o parâmetro pode ser string ou null -
Adicionado
: ?stringna declaração da função (type hint de retorno) -
Documentação mais clara dos comportamentos de entrada/saída
-
Adicionados exemplos práticos com
@example -
Documentação dos casos que retornam null
-
Menção explícita aos formatos suportados de entrada
Isso fornece uma documentação completa para:
-
Desenvolvedores que precisam usar a função
-
Ferramentas de IDE (como PHPStorm, VSCode)
-
Ferramentas de documentação automática
-
Análise estática de código
$validator = Validator::make($request->all(), [
'id_curso' => 'required|numeric',
'nome' => 'required|min:3|max:' . $tamanho_nome,
'nome_reduzido' => 'required|max:' . $tamanho_nome,
'coordenadores' => 'required',
'status' => 'required|in:A,I,D,P,T,J',
'ordem' => 'required|numeric',
'acesso_pergunte_professor' => 'required|in:S,N',
'destaque_home' => 'required|in:S,N',
'carga_horaria' => 'required|numeric',
'tempo_acesso' => 'required|numeric',
'data_inicio' => 'required',
'data_fim' => 'required',
'data_inicio_venda' => 'required',
'data_fim_venda' => 'required',
'acesso_individual' => 'numeric',
'cor' => 'string|required',
'categoria_curso' => 'required|in:oab_2fase,oab_1fase,interno,concursos,pratica,enem,pos_graduacao',
'tipo_curso' => 'required_unless:categoria_curso,interno|in:isolado,gratuito,plano,combo,cronograma,treinamento,repescagem,regular,assinatura,presencial,tcc,mentoria,extensivo,intensivo,imersao',
]);
Solução para Validação de Data
Parece que você está enfrentando dois problemas:
-
A data está sendo salva como
0000-00-00 00:00:00quando inválida -
Precisa validar se a data não é maior que 5 anos no futuro e se é uma data válida
Solução para o Validator
Vamos modificar seu validator para incluir as validações de data corretamente:
$validator = Validator::make($request->all(), [ 'id_curso' => 'required|numeric', 'nome' => 'required|min:3|max:' . $tamanho_nome, // ... outros campos ... 'data_fim' => [ 'required', 'date_format:d/m/Y H:i', function ($attribute, $value, $fail) { // Converte para objeto DateTime $data = DateTime::createFromFormat('d/m/Y H:i', $value); if (!$data) { $fail('O formato da data final é inválido.'); return; } // Verifica se a data não é mais que 5 anos no futuro $dataAtual = new DateTime(); $diferenca = $dataAtual->diff($data); if ($diferenca->y > 5) { $fail('A data final não pode ser mais que 5 anos no futuro.'); } // Verifica se a data é válida (não caiu no "0000-00-00") if ($data->format('Y') < 1000) { $fail('A data final informada é inválida.'); } } ], // ... outros campos de data com validação similar ... 'data_inicio' => [ 'required', 'date_format:d/m/Y H:i', function ($attribute, $value, $fail) { $data = DateTime::createFromFormat('d/m/Y H:i', $value); if (!$data) { $fail('O formato da data de início é inválido.'); } } ], // ... outros campos ... ]);
Solução para o Problema do "0000-00-00"
O problema ocorre porque a data está sendo passada para o banco em um formato inválido. Modifique seu helper para incluir validação:
/** * Converte uma data no formato brasileiro para o formato do banco de dados * com validação rigorosa */ public static function formataDatetimeParaBanco(?string $date): ?string { if (empty($date)) { return null; } // Tenta ambos os formatos (com e sem segundos) $datetime = DateTime::createFromFormat('d/m/Y H:i:s', $date); if ($datetime === false) { $datetime = DateTime::createFromFormat('d/m/Y H:i', $date); } // Se ainda falhar, retorna null para evitar data inválida if ($datetime === false) { return null; } // Verifica se o ano é válido (maior que 1000) if ($datetime->format('Y') < 1000) { return null; } return $datetime->format('Y-m-d H:i:s'); }
Validação Adicional no Controller
No seu controller, antes de salvar, você pode fazer uma validação adicional:
// Converter e validar a data $dataFim = Helpers::formataDatetimeParaBanco($request->data_fim); if (!$dataFim) { return back()->withErrors(['data_fim' => 'Data final inválida ou formato incorreto'])->withInput(); } // Verificar se a data não é mais que 5 anos no futuro $dataAtual = new DateTime(); $dataFimObj = new DateTime($dataFim); $diferenca = $dataAtual->diff($dataFimObj); if ($diferenca->y > 5) { return back()->withErrors(['data_fim' => 'A data final não pode ser mais que 5 anos no futuro'])->withInput(); } // Agora pode salvar com segurança $curso->data_fim = $dataFim;
Observações Importantes
-
Todas as validações devem ser feitas tanto no frontend quanto no backend
-
O MySQL/MariaDB rejeita datas inválidas (como '0000-00-00') em versões recentes
-
Considere usar campos
dateoudatetimeno banco de dados em vez de strings -
Para Laravel 8+, você pode usar as regras de validação embutidas como
after,beforeetc.
Donate to Site
Renato
Developer