Leco RP 6 Denunciar post Postado Julho 4, 2013 Fala galera, Estou montando um sistema de abertura de chamados e me surgiu a seguinte dúvida: como calcular prazo, considerando dias e horas úteis? Preciso calcular qual seria a data/hora após 6h, considerando dias e horas úteis (digamos assim) sendo que essas horas seriam o intervalo de 08:00 as 19:00 de segunda a sexta. Para cálculo de DIAS úteis, eu achei uma função da internet que funciona perfeitamente: function Feriados($ano,$posicao){ $dia = 86400; $datas = array(); $datas['pascoa'] = easter_date($ano); $datas['sexta_santa'] = $datas['pascoa'] - (2 * $dia); $datas['carnaval'] = $datas['pascoa'] - (47 * $dia); $datas['corpus_cristi'] = $datas['pascoa'] + (60 * $dia); $feriados = array ( '01/01', date('d/m',$datas['carnaval']), date('d/m',$datas['sexta_santa']), date('d/m',$datas['pascoa']), date('d/m',$datas['corpus_cristi']), '25/12', ); return $feriados[$posicao]."/".$ano; } // Formata como timestamp function dataToTimestamp($data){ $ano = substr($data, 6,4); $mes = substr($data, 3,2); $dia = substr($data, 0,2); return mktime(0, 0, 0, $mes, $dia, $ano); } // Soma 01 dia function Soma1dia($data){ $ano = substr($data, 6,4); $mes = substr($data, 3,2); $dia = substr($data, 0,2); return date("d/m/Y", mktime(0, 0, 0, $mes, $dia+1, $ano)); } function SomaDiasUteis($xDataInicial,$xSomarDias){ for($ii=1; $ii<=$xSomarDias; $ii++){ $xDataInicial=Soma1dia($xDataInicial); // Soma dia normal // Verifica se é dia útil if(date("w", dataToTimestamp($xDataInicial))=="0"){ // Se for domingo ou feriado , soma 01 $xDataInicial=Soma1dia($xDataInicial); }else if(date("w", dataToTimestamp($xDataInicial))=="6"){ // Se for sábado soma 02 $xDataInicial=Soma1dia($xDataInicial); $xDataInicial=Soma1dia($xDataInicial); }else{ // Verifica se é feriado for($i=0; $i<=12; $i++){ if($xDataInicial==Feriados(date("Y"),$i)){ $xDataInicial=Soma1dia($xDataInicial); } } } } // Retorna a data return $xDataInicial; } Agora a dúvida é como acrescentar as horas... Exemplificando: Cadastro um chamado em: 04-07-2013 18:50. Considerando as 6h "úteis", o prazo final para atender esse chamado seria 05-07-2013 13:50, ou seja, as 13h50m do dia seguinte. Agradeço desde já. Compartilhar este post Link para o post Compartilhar em outros sites
hufersil 145 Denunciar post Postado Julho 4, 2013 // objeto de data/hora // para indicar uma data/hora de inicio, passe ela no construtor, exemplo: // $date = new DateTime('2013-07-08 09:00:00'); $date = new DateTime(); // prazo, em horas. se precisar especificar em minutos, // coloque valores quebrados, como 15.5 $prazo = 30; // inicio do expediente 9 = horas * 60 para transformar em minutos $inicioExpediente = 9 * 60; // fim do expediente $fimExpediente = 19 * 60; // feriados $feriados = array('09/07/2013'); // dias encontrados para trampo $diasUteis = array(); // ----------- agora começa a brincadeira // convertemos o prazo para minutos $prazoMinutos = $prazo * 60; // enquanto for maior que zero while( $prazoMinutos > 0 ){ // transformamos a hora atual em minutos $hora = ($date->format('H') * 60) + $date->format('i'); // se for menor que a hora do inicio do expediente if($hora < $inicioExpediente){ // colocamos igual a hora do expediente $date->setTime(0, $inicioExpediente, 0); continue; } // data calculada $data = $date->format('d/m/Y'); // se // - for um feriado OU // - passar da hora do expediente OU // - for um dia de fim de semana (sabado|domingo) // vamos para o dia seguinte, no inicio do expediente if(in_array($data,$feriados) || $hora >= $fimExpediente || $date->format('w') == 0 || $date->format('w') == 6){ $date->modify('+1 day'); $date->setTime(0, $inicioExpediente, 0); continue; } // se chegou aqui, é um dia util. // vamos ver se já está na nossa lista de dias // se não estiver, colocamos if(!in_array($data, $diasUteis)){ $diasUteis[] = $data; } // minutos que temos que acrescentar para chegar no // fim do expediente de hoje $minutos = $fimExpediente - $hora; // tiramos do prazo $prazoMinutos -= $minutos; // se estourou if($prazoMinutos < 0){ // tiramos o que estourou $minutos += $prazoMinutos; } // adicionamos os minutos do calculo na data $date->modify('+' . $minutos . ' minute'); } echo $prazoFinal = $date->format('d/m/Y H:i:s'), PHP_EOL; print_r($diasUteis); [ Editado ] Otimização no código. Estava meio lento quando o prazo era grande. @braços e fiquem com Deus! Compartilhar este post Link para o post Compartilhar em outros sites
hufersil 145 Denunciar post Postado Julho 4, 2013 Noooossa.... Eu já tinha respondido aqui no fórum uma dúvida parecida com a sua... em 2010 kkkk http://forum.imasters.com.br/topic/403328-trabalhando-com-horas-teis/ Como as coisas mudam :D @braços Compartilhar este post Link para o post Compartilhar em outros sites
Leco RP 6 Denunciar post Postado Julho 4, 2013 E olha que eu procurei pelo fórum, hein? Muito obrigado pela ajuda Hugo! Fiz uns testes e funcionou perfeitamente. Fiquei com uma dúvida: é possível "fundir" com a função de cálculo de dias úteis que mencionei no primeiro post? Pergunto pois lá já estão previstos todos os feriados (só falta acrescentar o restante) e independe do ano, ou seja, para qualquer ano basta acrescentar os dias sem que seja necessário mudar o código para cada ano. Mais uma vez, muito obrigado pela ajuda, Hugo! :clap: Compartilhar este post Link para o post Compartilhar em outros sites
hufersil 145 Denunciar post Postado Julho 5, 2013 Mas esta que passei já separa os dias úteis, no array $diasUteis. Sobre os feriados, também coloquei ali um array com as datas que podem ser feriados (que no caso, o próximo dia 09/07/2013 é feriado em São Paulo). Se quiser mais, é só acrescentar a data ao array. $feriados = array('09/07/2013','25/12/2013','07/09/2013'); @braços Compartilhar este post Link para o post Compartilhar em outros sites
Leco RP 6 Denunciar post Postado Julho 5, 2013 Fala Hugo, Essa parte eu entendi, inclusive completei o vetor com os feriados até o fim do ano. Coloquei essa possibilidade de fundir com a outra função, pois nela não é preciso colocar o ano. Ela me retorna o dia útil referente a qualquer ano... Seria mais um "complemento", digamos assim. Abraços Compartilhar este post Link para o post Compartilhar em outros sites
hufersil 145 Denunciar post Postado Julho 5, 2013 É porque aquela função só calcula os feriados móveis. Os fixos não estão lá. Logo, é só você complementar a lista de feriados que está na função que te passei com os feriados fixos e que estão na função que você pegou (adicionando o ano na data). @braços Compartilhar este post Link para o post Compartilhar em outros sites
Leco RP 6 Denunciar post Postado Julho 6, 2013 Olá Hugo, Se observar, os fixos estão também, veja: function Feriados($ano,$posicao){ $dia = 86400; $datas = array(); $datas['pascoa'] = easter_date($ano); $datas['sexta_santa'] = $datas['pascoa'] - (2 * $dia); $datas['carnaval'] = $datas['pascoa'] - (47 * $dia); $datas['corpus_cristi'] = $datas['pascoa'] + (60 * $dia); $feriados = array ( '01/01', // Primeiro dia do ano date('d/m',$datas['carnaval']), date('d/m',$datas['sexta_santa']), date('d/m',$datas['pascoa']), date('d/m',$datas['corpus_cristi']), '25/12', // Natal ); Seria só complementar os que estão faltando... Certo? Abraços Compartilhar este post Link para o post Compartilhar em outros sites
HBLSYS 0 Denunciar post Postado Março 8, 2014 // objeto de data/hora // para indicar uma data/hora de inicio, passe ela no construtor, exemplo: // $date = new DateTime('2013-07-08 09:00:00'); $date = new DateTime(); // prazo, em horas. se precisar especificar em minutos, // coloque valores quebrados, como 15.5 $prazo = 30; // inicio do expediente 9 = horas * 60 para transformar em minutos $inicioExpediente = 9 * 60; // fim do expediente $fimExpediente = 19 * 60; // feriados $feriados = array('09/07/2013'); // dias encontrados para trampo $diasUteis = array(); // ----------- agora começa a brincadeira // convertemos o prazo para minutos $prazoMinutos = $prazo * 60; // enquanto for maior que zero while( $prazoMinutos > 0 ){ // transformamos a hora atual em minutos $hora = ($date->format('H') * 60) + $date->format('i'); // se for menor que a hora do inicio do expediente if($hora < $inicioExpediente){ // colocamos igual a hora do expediente $date->setTime(0, $inicioExpediente, 0); continue; } // data calculada $data = $date->format('d/m/Y'); // se // - for um feriado OU // - passar da hora do expediente OU // - for um dia de fim de semana (sabado|domingo) // vamos para o dia seguinte, no inicio do expediente if(in_array($data,$feriados) || $hora >= $fimExpediente || $date->format('w') == 0 || $date->format('w') == 6){ $date->modify('+1 day'); $date->setTime(0, $inicioExpediente, 0); continue; } // se chegou aqui, é um dia util. // vamos ver se já está na nossa lista de dias // se não estiver, colocamos if(!in_array($data, $diasUteis)){ $diasUteis[] = $data; } // minutos que temos que acrescentar para chegar no // fim do expediente de hoje $minutos = $fimExpediente - $hora; // tiramos do prazo $prazoMinutos -= $minutos; // se estourou if($prazoMinutos < 0){ // tiramos o que estourou $minutos += $prazoMinutos; } // adicionamos os minutos do calculo na data $date->modify('+' . $minutos . ' minute'); } echo $prazoFinal = $date->format('d/m/Y H:i:s'), PHP_EOL; print_r($diasUteis); [ Editado ] Otimização no código. Estava meio lento quando o prazo era grande. @braços e fiquem com Deus! Cara, muito bom o fonte, porém ao final preciso armazenar a Data Fim em uma variável, pois depois preciso gravar no banco. E não simplesmente exibir em tela. Como faço? Compartilhar este post Link para o post Compartilhar em outros sites
xurissoooo 10 Denunciar post Postado Março 8, 2014 PHP - Somar ou Subtrair dias de uma data Adicionar♦ 10 dias a partir de hoje echo date('d/m/Y', strtotime("+10 days")); ♦ 10 dias a partir de uma data echo date('d/m/Y', strtotime("+10 days",strtotime('20-07-2011'))); Subtrair ♦ 10 dias a partir de hoje echo date('d/m/Y', strtotime("-10 days")); ♦ 10 dias a partir de uma data echo date('d/m/Y', strtotime("-10 days",strtotime('20-07-2011'))); Compartilhar este post Link para o post Compartilhar em outros sites