Ir para conteúdo

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

hwrry

[Resolvido] CALCULO DE HORAS PARADAS

Recommended Posts

 Bom dia! Preciso realizar um calculo que me retorne a quantidade de horas que uma maquina ficou parada, em meu banco de dados tenho dois campo data/minutos, que são de data parada e data retorno, os mesmos estão no seguinte formato:


 

$dataIni = '201704120850' ;

 $dataFim = '201704120955';

 

Até ai consigo fazer o cálculo com a seguinte função:       

$dtIni = '201704120850';
        $dtFim = '201704120955';  
        
        $datatime1 = new DateTime($dtIni);
        $datatime2 = new DateTime($dtFim);
       

        $data1  = $datatime1->format('Y-m-d H:i:s');
        $data2  = $datatime2->format('Y-m-d H:i:s');  
             
        $data1 = strtotime($data1);
        $data2 = strtotime($data2);
        
        $nHoras   = ($data2 - $data1) / 3600;
        $nMinutos = (($data2 - $data1) % 3600) / 60;
        $total = sprintf('%02d:%02d', $nHoras , $nMinutos);

        echo $total;

 

O problema agora é que preciso levar em consideração apenas o horário de funcionamento das maquinas que seria das 07:30 até 12:00 e das 13:30 as 17:48, e desconsiderar os sábados, domingos e feriados.

Compartilhar este post


Link para o post
Compartilhar em outros sites

@hwrry O esquema que segue, faz o calculo das horas e desconsidera finais de semana e feriados;

Não entendi muito bem o cenário do horário de funcionamento das maquinas. Elas são desligadas todos os dias? Pode ter logs que por exemplo, inicia em 201705010800 e termine em 201705051700, ou seja, com mais de um dia? Se tiver dificuldades para implementar essa parte, de mais detalhes desse cenário!?

function diaUtil($data, $feriados)
{
    /** 
        Verifica se a data corresponde a um final de semana
    */
    if( stristr('Sunday, Saturday', $data->format('l'))) {
        return false;
    } 
    /** 
        verifica se a data corresponde a um feriado 
    */    
    if (in_array($data->format('md'), $feriados)) {
        return false;
    }
    return true;
}

function calculaIntevaloDeHorasEmDiasUteis($dataInicio, $dataFim, $feriados) {
    $dataInicio = new \DateTime($dataInicio);
    if (diaUtil($dataInicio, $feriados)) {
        $dataFim = new \DateTime($dataFim);
        return $dataInicio->diff($dataFim)->format("%H:%I:%S");
    }    
}

/*
Como os feriados estaduais e municipais variam de região para região, complete o array abaixo
de acordo com o seu caso.
Dica: Para ficar melhor organizado, crie um arquivo feriados.php e depois faça o include
*/

$feriados = [
            '0101',
            '2802',
            '1404',
            '1604',
            '2104',
        ];    

$dataInicio = '201704120850' ;

$dataFim = '201704120955';

echo calculaIntevaloDeHorasEmDiasUteis($dataInicio, $dataFim, $feriados); // 01:05

 

Compartilhar este post


Link para o post
Compartilhar em outros sites

 Boa tarde a função que retorna as horas úteis desconsiderando finais de semana e feriados eu consegui fazer hoje, o meu problema agora é justamente a questão das horas, pois as maquinas funcionam apenas  das 07:30 até 12:00 e das 13:30 as 17:48,

portando as horas contabilizadas fora desses períodos devem ser subtraídas do total.  Segue meu código fonte atualizado.


 

public function horas_paradas(){   
    
        //define que não serão utilizado a view para estão requisição
        $this->autoRender = $this->layout = false;
        
        $feriado = '20170416';
        
        $inicio1 = '07:30';
        $fim1 = '12:00';  
        $inicio2 = '13:30';
        $fim2 = '17:48';
        
        $dtIni = '201704120850';
        $dtFim = '201704170851';   
        
        $datatime1 = new DateTime($dtIni);
        $datatime2 = new DateTime($dtFim);   

        $data1  = $datatime1->format('Y-m-d H:i:s');
        $data2  = $datatime2->format('Y-m-d H:i:s');  
        
        $diasUteis = $this->_getDiasUteis($data1, $data2);  
        
       $total = $diasUteis * 24;
        echo $total; die;
        
        
    }
    
    function _getDiasUteis($dataIni, $dataFim) {
        $dataIni = substr($dataIni,0,10);
        $dataFim = substr($dataFim,0,10);
        $inicio = strtotime($dataIni);
        $fim   = strtotime($dataFim);  
        $ano = date("Y",$inicio);
        
        $feriados = array(
            strtotime($ano.'-04-16') => 'Teste',  //1492343400 //1492311600
            strtotime($ano.'-01-01') => 'Confraternização Universal',  
            strtotime($ano.'-02-27') => 'Carnaval',   
            strtotime($ano.'-02-28') => 'Carnaval',   
            strtotime($ano.'-04-14') => 'Paixão de Cristo',   
            strtotime($ano.'-04-21') => 'Tiradentes',   
            strtotime($ano.'-05-01') => 'Dia do Trabalho',   
            strtotime($ano.'-06-15') => 'Corpus Christi',   
            strtotime($ano.'-09-07') => 'Independência do Brasil',   
            strtotime($ano.'-10-12') => 'Nossa Sr.a Aparecida',   
            strtotime($ano.'-11-02') => 'Finados',   
            strtotime($ano.'-11-15') => 'Proclamação da República',   
            strtotime($ano.'-12-25') => 'Natal'  
        );   

        if ($inicio > $fim) {
            return 0;
        } else {
            $qtdDias  = 0;
            $qtdFds = 0;
            $qtdFeriados = 0;
            while ($inicio <= $fim) {
                $qtdDias++;
                $dia = date("N", $inicio);
                if ($dia > 5) { // 6-Sábado - 7-Domingo
                    $qtdFds++;
                }
                
                if(array_key_exists($inicio, $feriados) && $dia <= 5) {
                    $qtdFeriados++;
                }
                
                $inicio += 86400; // +1 dia
            }
            $diasUteis = $qtdDias - $qtdFds - $qtdFeriados;

            return $diasUteis;
        }
    } 

 

Compartilhar este post


Link para o post
Compartilhar em outros sites

Se entendi o seu problema, você não precisa subtrair os horários invalido, por exemplo:
Se a entrada for 06:20, você ajusta para 07:30;

Se a saída for 20:00, você ajusta para 17:48. "De certa forma é uma subtração"

Veja se te atende:

function diaUtil($data, $feriados)
{
    /** 
        Verifica se a data corresponde a um final de semana
    */
    if( stristr('Sunday, Saturday', $data->format('l'))) {
        return false;
    } 
    /** 
        verifica se data corresponde a um feriado 
    */    
    if (in_array($data->format('md'), $feriados)) {
        return false;
    }
    return true;
}

function calculaIntevaloDeHorasEmDiasUteis($dataInicio, $dataFim, $feriados) {
    $dataInicio = new \DateTime($dataInicio);
    
    if (diaUtil($dataInicio, $feriados)) {
        $dataFim = new \DateTime($dataFim);

        $horariosValidos = ajustaHorario($dataInicio, $dataFim);
        
        $dataInicio->setTime(substr($horariosValidos[0], 0,2), substr($horariosValidos[0], 2,4) );
        $dataFim->setTime(substr($horariosValidos[1], 0,2), substr($horariosValidos[1], 2,4) );
        
        return $dataInicio->diff($dataFim)->format("%H:%I:%S");
    }    
}

function ajustaHorario($dataInicio, $dataFim)
{
    $horarioInicio = $dataInicio->format("Hi");
    $horarioFim = $dataFim->format("Hi");

    if ($horarioInicio < '0730') {
        $horarioInicio = '0730';
    }
    elseif ($horarioInicio > '1748') {
        $horarioInicio = '1748';
    }
    elseif ($horarioInicio > '1200' and $horarioInicio < '1330') {
        $horarioInicio = '1330';
    }
                                                          
                                                          
    if ($horarioFim < '0730') {
        $horarioFim = '0730';
    }
    elseif ($horarioFim > '1748') {
        $horarioFim = '1748';
    }
    elseif ($horarioFim > '1200' and $horarioFim < '1330') {
        $horarioFim = '1330';
    } 
    return [$horarioInicio, $horarioFim];
}

$feriados = [
            '0101',
            '2802',
            '1404',
            '1604',
            '2104',
            '0501',
        ];    

echo calculaIntevaloDeHorasEmDiasUteis('201705050830', '201705050850', $feriados);
# ira exibir: 00:20:00
                                                    
echo calculaIntevaloDeHorasEmDiasUteis('201705051330', '201705051450', $feriados);
# ira exibir: 01:20:00
                                                    
echo calculaIntevaloDeHorasEmDiasUteis('201705050630', '201705051250', $feriados);
# ira exibir: 06:00:00
                                                    
echo calculaIntevaloDeHorasEmDiasUteis('201705051210', '201705051850', $feriados);
# ira exibir: 04:18:00
                                                    
echo calculaIntevaloDeHorasEmDiasUteis('201705050510', '201705050650', $feriados);
# ira exibir: 00:00:00
                                                    
echo calculaIntevaloDeHorasEmDiasUteis('201705051910', '201705052050', $feriados);
# ira exibir: 00:00:00

 

Compartilhar este post


Link para o post
Compartilhar em outros sites

 Estava testando aqui alguns outros períodos e em alguns está retornando a quantidade errada.

 Por exemplo:

 

$dtIni = '201704121159';
$dtFim = '201704121331';    

 

está retornando 01:32, quando deveria ser apenas 2 minutos, pois o restante do tempo ocorreu durante o intervalo. Tentei mexer nas validações da função ajustaHorario o dia inteiro, mas não consegui chegar em uma solução.

Compartilhar este post


Link para o post
Compartilhar em outros sites

@hwrry tem varias formas de resolver, veja se essa ideia fica legal. Adicione no final de ajustaHorario(), antes do return
 

elseif($horarioInicio < '1200' and $horarioFim > '1330'){
    $horarioInicio += '0130';
}

Como no final sera feito uma subtração do final com o inicio, eu adiciono o período das 12:00 às 13:30, que corresponde a uma hora e meia, no horário inicial, que servira como debito.

Acredito que com mais essa adição, todos os cenários ficam cobertos.

Compartilhar este post


Link para o post
Compartilhar em outros sites
40 minutos atrás, EdCesar disse:

Acredito que com mais essa adição, todos os cenários ficam cobertos.

 

Ops, na verdade tem mais um caso. Adicione também no final de ajustaHorario(), antes do return
 

if($horarioInicio < '1200' and $horarioFim > '1200' and $horarioFim <= '1330'){
    $horarioFim = '1200';
} 

Daria erro nesse cenário:

echo calculaIntevaloDeHorasEmDiasUteis('201704121150', '201704121320', $feriados) . PHP_EOL;

 

Compartilhar este post


Link para o post
Compartilhar em outros sites

  • Conteúdo Similar

    • Por Diego-SLP
      Bom dia,
       
      Estou fazendo uma tela de relatorios de registro de ponto e não estou conseguindo totalizar as horas conforme trago do banco de dados, se alguem puder me ajudar.
       
      SELECT p.cod_obra,f.nome,o.obra, TIME_FORMAT(SEC_TO_TIME(SUM(TIME_TO_SEC(p.totalhora))),'%H:%i') AS hora, TIME_FORMAT(SEC_TO_TIME(SUM(TIME_TO_SEC(p.totalhoraextra))),'%H:%i') AS horaextra, f.funcao FROM rh_pontoFuncionario p, rh_funcionario f, rh_obra o WHERE p.data BETWEEN '2020/10/01' AND '2020/11/20' AND p.cod_obra = '20056' AND p.cod_func = f.cod AND p.cod_obra = o.cod GROUP BY p.cod_obra, f.nome Essa query me traz COD_OBRA,NOME,OBRA,HORA,HORAEXTRA,FUNCAO e eu gostaria de TOTALIZAR o campo HORA e HORAEXTRA somando todas as linhas mas não consigo
    • Por helkton
      oi galera tudo joinha, estou em um dilema faz horas aqui, seguinte....
      estou em um projeto para uma empresa de cursos, estou querendo fazer o seguinte, eu cadastro em meu banco MYSQL os dados do aluno, por exemplo as horas que o aluno já fez o curso
      exemplo.... tenho em meu banco a seguinte coluna - > horaPraticaCargaHoraria e a coluna horaTeoricaCargaHoraria - são campos time, ou seja só gravo as horas que o aluno já fez o curso
      então o que quero é o seguinte, somar todas as horasPraticas que o aluno já fez e depois também as horasTeoricas ai depois eu faço o if para as devidas condiçoes tipo, se o aluno a concluiu as horas pratica e teoricas esta liberado para imprimir o certificado, se não ainda não
      tipo cada curso tem a sua determinada carga horaria PRATICA e TEORICA
      explicando o que já fiz
      <?php $consultCursoAluno = "select * from cursos inner join curso_escolhido ON (cursos.idCurso = curso_escolhido.idCursoPretendidoEscolhido) where idCursoAlunoEscolhido = '$idAluno' and checkedCursoEscolhido = '1'"; $conectaCursoAluno = $conecta->query($consultCursoAluno); while($resultCursoAluno = $conectaCursoAluno->fetch_object()){?> NomeCurso:<?php echo $resultCursoAluno->nomeCurso?>//Consigo pegar os cursos que o aluno está fazendo <br> <?php $sqlCurso = "select * from carga_horaria where idAlunoCargaHoraria = '$idAluno' and idCursoCargaHoraria = '".$resultCursoAluno->idCurso."'"; $conectaCurso = $conecta->query($sqlCurso); $soma = 0; while($result = $conectaCurso->fetch_object()){//nesse while ele está transformando as horas em string e somando ele me da as horas em segundos total $horaPra = strtotime($result->horaPraticaCargaHoraria); $soma += $horaPra; $total = $soma;?> HoraNormal - <?php echo $result->horaPraticaCargaHoraria?> - - - HoraString (<?php echo $horaPra?>) <br> <?php }?> <?php echo $soma?>//O problema esta aqui, quando vou transformar esta hora que esta em segundos para a hora normal (date('H:i:s', $soma)) não transforma e quando transforma fica tipo com um hora a mais, ai da uma bagunçada <br> <?php }?>  
    • Por joazinDev
      Estou tentando calcular duas horas e as vezes precisso que ela saia negativa tbm
      Exemplo:
      07:33 - 07:48 = -00:15
      Como faço isso utilizando php ?
    • Por Viniciusr9
      Boa tarde pessoal,
      basicamente eu preciso do retorno de horas entre duas datas, porém tenho condições a tratar .
      basicamente tenho 2 colunas ( dt_fim e dt_ini ) que representam data final e data inicial. Preciso da diferença entre as duas retornada em uma outra coluna (hr_ausencias) , porém a cada dia posso computar no máximo 9 horas, e desconsiderar finais de semana e feriados( esses cadastrados em uma tabela) . Seria melhor tratar isso com uma Trigger , um Script PL/SQL , como me sugerem? Agradeço quem puder ajudar.
    • Por marcosberaldo
      Boa noite.
       
      Estou criando um ranking de pontuação e preciso colocar uma paginação nesse ranking mas não posso fazer a paginação pelo select, pois a select tem que somar os pontos de cada jogador informados em cada registro no banco, se eu limito a select ele só vai somar os pontos dos registros da página e não todos os pontos do jogador.
       
      Dessa forma optei por fazer a select normalmente e criar um array onde eu pretendo exibir somente parte dos dados.
       
      Em resumo, consegui fazer da seguinte forma:
      $dados = mysqli_query($conn, "SELECT *, sum(Pontos) as TotalPontos, sum(Acerto_Exato) as Acertos FROM placares INNER JOIN jogadores ON placares.JogadorID = jogadores.id WHERE campeonato='$campeonato' GROUP BY JogadorID ORDER BY TotalPontos DESC, Acertos DESC "); for($a = 0; $a < 9; $a++ ) { $row = mysqli_fetch_array($dados); echo $row['JogadorID']. " - " .$row['nome']; } Esse código me retorna 10 registros do array, até ai tudo bem, mas eu gostaria de exibir apenas um intervalo, por exemplo do registro 5 ao 9. 
      Tentei da seguinte forma:
      $dados = mysqli_query($conn, "SELECT *, sum(Pontos) as TotalPontos, sum(Acerto_Exato) as Acertos FROM placares INNER JOIN jogadores ON placares.JogadorID = jogadores.id WHERE campeonato='$campeonato' GROUP BY JogadorID ORDER BY TotalPontos DESC, Acertos DESC "); for($a = 5; $a < 9; $a++ ) { $row = mysqli_fetch_array($dados); echo $row['JogadorID']. " - " .$row['nome']; } Dessa forma ele me mostra apenas 5 registros, mas ele sempre me mostra os 5 primeiros e eu preciso carregar os últimos 5.
       
      Como faço???
×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.