Somar dias úteis em data - PHP

Publicado por Ricardo Herrero em 02/12/2010

[ Hits: 18.421 ]

 


Somar dias úteis em data - PHP



Olá amigos.

Vamos fazer um novo exercício com datas, agora somando dias úteis em uma determinada data.

Vou utilizar as mesmas bibliotecas que usamos para a dica anterior: Cálculo de dias úteis entre duas datas em PHP

Bem, vamos direto aos códigos. Neste exemplo vamos criar algumas funções que vão facilitar nosso trabalho.

Descritivo das funções:

<?
//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);  
}
?>

Esta função irá transformar a data que iremos utilizar, conforme padrão mktime.

<? //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));
}
?>

Esta função efetua a soma de um dia para uma data qualquer.

<?
//LISTA DE FERIADOS NO ANO
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',
      '02/02', // Navegantes
      date('d/m',$datas['carnaval']),
      date('d/m',$datas['sexta_santa']),
      date('d/m',$datas['pascoa']),
      '21/04',
      '01/05',
      date('d/m',$datas['corpus_cristi']),
      '20/09', // Revolução Farroupilha \m/
      '12/10',
      '02/11',
      '15/11',
      '25/12',
   );
        
return $feriados[$posicao]."/".$ano;
}
?>

Vamos registrar todos os possíveis feriados dentro deste array.

Vocês podem perceber que temos datas de feriados fixos, por exemplo, o natal que é sempre no dia 25 de dezembro e também temos feriados como a páscoa, que precisamos fazer um cálculo para descobrirmos o dia certo do feriado.

Com estas 03 funções acima conseguiremos efetuar a nossa soma de dias úteis.

Segue abaixo a função que fará esta soma:

<?
function SomaDiasUteis($xDataInicial,$xSomarDias){
   for($ii=1; $ii<=$xSomarDias; $ii++){
      
      $xDataInicial=Soma1dia($xDataInicial); //SOMA DIA NORMAL
      
      //VERIFICANDO SE EH DIA DE TRABALHO
      if(date("w", dataToTimestamp($xDataInicial))=="0"){
         //SE DIA FOR DOMINGO OU FERIADO, SOMA +1
         $xDataInicial=Soma1dia($xDataInicial);
        
      }else if(date("w", dataToTimestamp($xDataInicial))=="6"){
         //SE DIA FOR SABADO, SOMA +2
         $xDataInicial=Soma1dia($xDataInicial);
         $xDataInicial=Soma1dia($xDataInicial);
        
      }else{
         //senaum vemos se este dia eh FERIADO
         for($i=0; $i<=12; $i++){
            if($xDataInicial==Feriados(date("Y"),$i)){
               $xDataInicial=Soma1dia($xDataInicial);
            }
         }
      }
   }
return $xDataInicial;
}
?>

Iremos fazer uma verificação dia-a-dia para saber se o dia é útil.

Através da função PHP date, utilizamos o parâmetro w que irá retornar o valor 6 para sábado ou 0 para domingo. Caso esta informação seja falsa, conferimos se a data não é um feriado.

Para efetuarmos a chamada da função que realiza a soma, basta executar a função SomaDiasUteis(a,b), conforme exemplo abaixo.

Desejamos somar 02 dias úteis a partir da data de hoje:

<?= SomaDiasUteis(date("d/m/Y"),5)?>

Galera, é isso. Espero ter ajudado com este código.

Fico no aguardo dos comentários e sugestões para os próximos.

Para visualizar este código funcionando, use o link:
Em breve estarei publicando uma biblioteca que utilizo para efetuar upload de imagem.

Ricardo Herrero
Desenvolvedor web PHP

Abaixo segue o código completo.

Data-SomaDiasUteis.PHP:

<?
//CALCULANDO DIAS NORMAIS
      //LISTA DE FERIADOS NO ANO
      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',
            '02/02', // Navegantes
            date('d/m',$datas['carnaval']),
            date('d/m',$datas['sexta_santa']),
            date('d/m',$datas['pascoa']),
            '21/04',
            '01/05',
            date('d/m',$datas['corpus_cristi']),
            '20/09', // Revolução Farroupilha \m/
            '12/10',
            '02/11',
            '15/11',
            '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
            
            //VERIFICANDO SE EH DIA DE TRABALHO
            if(date("w", dataToTimestamp($xDataInicial))=="0"){
               //SE DIA FOR DOMINGO OU FERIADO, SOMA +1
               $xDataInicial=Soma1dia($xDataInicial);
              
            }else if(date("w", dataToTimestamp($xDataInicial))=="6"){
               //SE DIA FOR SABADO, SOMA +2
               $xDataInicial=Soma1dia($xDataInicial);
               $xDataInicial=Soma1dia($xDataInicial);
              
            }else{
               //senaum vemos se este dia eh FERIADO
               for($i=0; $i<=12; $i++){
                  if($xDataInicial==Feriados(date("Y"),$i)){
                     $xDataInicial=Soma1dia($xDataInicial);
                  }
               }
            }
         }
      return $xDataInicial;
      }
?>  
<HTML>      
<?
$DataInicial = "04/08/2010";
$QtdDia = 8;
$diasSomados = SomaDiasUteis($DataInicial,$QtdDia);
?>
  
   <BODY>
      <br />
      Somar <?=$QtdDia?> dia(s) de <?=$DataInicial?> = Resultado: <?=$diasSomados?>   ?>
      
   </BODY>
</HTML>

Outras dicas deste autor

Calculo de dias úteis entre duas datas em PHP

Leitura recomendada

Instalando Debian em servidores DELL

Configurando servidor DHCP3

Customizando Splash Screen do Grub

Desenvolvimento de Lista Encadeada Dinâmica Genérica

Arch Linux - Limpeza de pacotes

  

Comentários
[1] Comentário enviado por engalexsandro em 24/01/2013 - 17:34h

Prezado Ricardo. Este Script salvou minha vida... valew d+......... Porém ao testar algumas datas, percebi que este script possui uma falha: não calcula se o feriado cair na Segunda, veja o exemplo: Neste ano (2013) o Carnaval é na 12/02 e 11/02 para mim também não é dia útil, cadastrei essa dara no array feriados, mas como o dia 09/02/2013 cai no sábado, o script soma mais 2 (11/02/2013) e não testa se é feriado e considera dia 11/02 como útil. Fiz a seguinte modificação:

function SomaDiasUteis($xDataInicial,$xSomarDias){
for($ii=1; $ii<=$xSomarDias; $ii++){

$xDataInicial=$this->Soma1dia($xDataInicial); //SOMA DIA NORMAL

//VERIFICANDO SE EH DIA DE TRABALHO
if(date("w", $this->dataToTimestamp($xDataInicial))=="0"){
//SE DIA FOR DOMINGO OU FERIADO, SOMA +1
$xDataInicial=$this->Soma1dia($xDataInicial);

}else if(date("w", $this->dataToTimestamp($xDataInicial))=="6"){
//SE DIA FOR SABADO, SOMA +2
$xDataInicial=$this->Soma1dia($xDataInicial);
$xDataInicial=$this->Soma1dia($xDataInicial);

}
//Este dia eh FERIADO
for($i=0; $i<=13; $i++){
var_dump($xDataInicial,$xDataInicial==$this->Feriados(date("Y"),$i));
echo "<br />";

if($xDataInicial==$this->Feriados(date("Y"),$i)){
$xDataInicial=$this->Soma1dia($xDataInicial);
}
}
}
return $xDataInicial;
}

Abraços.

[2] Comentário enviado por alanjr em 08/06/2015 - 17:11h

Olá Ricardo, só da uma verificada na função SomaDiasUteis, eu inverti a sua lógica.

Primeiro verifiquei se o dia é feriado, aí depois verifico se é sabado ou domingo, estava dando erros em algumas datas, depois que fiz isso começou a funcionar corretamente, abaixo a mudança que fiz.

function SomaDiasUteis($xDataInicial,$xSomarDias){
for($ii=1; $ii<=$xSomarDias; $ii++){
$xDataInicial=Soma1dia($xDataInicial);
for($i=0; $i<13; $i++){
var_dump($xDataInicial,$xDataInicial==Feriados(date("Y"),$i));
echo "<br />";

if($xDataInicial==Feriados(date("Y"),$i)){
$xDataInicial=Soma1dia($xDataInicial);
}else{
//VERIFICANDO SE EH DIA DE TRABALHO
if(date("w",dataToTimestamp($xDataInicial))=="0"){
//SE DIA FOR DOMINGO OU FERIADO, SOMA +1
$xDataInicial=Soma1dia($xDataInicial);

}else if(date("w", dataToTimestamp($xDataInicial))=="6"){
//SE DIA FOR SABADO, SOMA +2
$xDataInicial=Soma1dia($xDataInicial);
$xDataInicial=Soma1dia($xDataInicial);
}
}
}
}
return $xDataInicial;
}

Até mais!

[3] Comentário enviado por GCONTABIL em 08/02/2016 - 02:15h

Como ficaria a função para se a data final fosse o sábado, domingo ou feriado pulasse para o primeiro dia útil?

Alguém pode ajudar.

[4] Comentário enviado por GCONTABIL em 13/03/2016 - 19:47h


[2] Comentário enviado por alanjr em 08/06/2015 - 17:11h

Olá Ricardo, só da uma verificada na função SomaDiasUteis, eu inverti a sua lógica.

Primeiro verifiquei se o dia é feriado, aí depois verifico se é sabado ou domingo, estava dando erros em algumas datas, depois que fiz isso começou a funcionar corretamente, abaixo a mudança que fiz.

function SomaDiasUteis($xDataInicial,$xSomarDias){
for($ii=1; $ii&lt;=$xSomarDias; $ii++){
$xDataInicial=Soma1dia($xDataInicial);
for($i=0; $i&lt;13; $i++){
var_dump($xDataInicial,$xDataInicial==Feriados(date("Y"),$i));
echo "&lt;br /&gt;";

if($xDataInicial==Feriados(date("Y"),$i)){
$xDataInicial=Soma1dia($xDataInicial);
}else{
//VERIFICANDO SE EH DIA DE TRABALHO
if(date("w",dataToTimestamp($xDataInicial))=="0"){
//SE DIA FOR DOMINGO OU FERIADO, SOMA +1
$xDataInicial=Soma1dia($xDataInicial);

}else if(date("w", dataToTimestamp($xDataInicial))=="6"){
//SE DIA FOR SABADO, SOMA +2
$xDataInicial=Soma1dia($xDataInicial);
$xDataInicial=Soma1dia($xDataInicial);
}
}
}
}
return $xDataInicial;
}

Até mais!


Esta função não funciona quanto acrescentamos mais feriados, veja a baixo o código após acrescentar os recesso dia 01 a 06/01. A função não calcula correto? Alguém pode ajudar:

<?
//CALCULANDO DIAS NORMAIS
//LISTA DE FERIADOS NO ANO
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', //Recesso 20/12 a 06/01
'02/01',
'03/01',
'04/01',
'05/01',
'06/01',
'02/02', // Navegantes
date('d/m',$datas['carnaval']),
date('d/m',$datas['sexta_santa']),
date('d/m',$datas['pascoa']),
'21/04',
'01/05',
'20/06',
'24/06',
date('d/m',$datas['corpus_cristi']),
'20/09', // Revolução Farroupilha \m/
'12/10',
'02/11',
'15/11',
'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);
for($i=0; $i<13; $i++){
var_dump($xDataInicial,$xDataInicial==Feriados(date("Y"),$i));
echo "<br />";

if($xDataInicial==Feriados(date("Y"),$i)){
$xDataInicial=Soma1dia($xDataInicial);
}else{
//VERIFICANDO SE EH DIA DE TRABALHO
if(date("w",dataToTimestamp($xDataInicial))=="0"){
//SE DIA FOR DOMINGO OU FERIADO, SOMA +1
$xDataInicial=Soma1dia($xDataInicial);

}else if(date("w", dataToTimestamp($xDataInicial))=="6"){
//SE DIA FOR SABADO, SOMA +2
$xDataInicial=Soma1dia($xDataInicial);
$xDataInicial=Soma1dia($xDataInicial);
}
}
}
}
return $xDataInicial;
}


?>
<HTML>
<?
$DataInicial = "31/12/2016";
$QtdDia = 1;
$diasSomados = SomaDiasUteis($DataInicial,$QtdDia);

?>

<BODY>
<br />
Somar <?=$QtdDia?> dia(s) Uteis a data inicial <?=$DataInicial?> = Resultado: <?=$diasSomados?>


</BODY>
</HTML>



Contribuir com comentário