Ir para conteúdo
Rui Sérgio

Calcular diferença de datas em dias uteis?

Recommended Posts

Tem uma função que você pega o dia da semana, aí vai ter que comparar se é sabado ou domingo. E aí não contabiliza. Quanto a feriado não sei como fazer. Talvez se você tiver todos cadastrados.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Tem uma função que você pega o dia da semana, aí vai ter que comparar se é sabado ou domingo. E aí não contabiliza. Quanto a feriado não sei como fazer. Talvez se você tiver todos cadastrados.

Criei uma função para calcular dias uteis entre duas datas informadas...Vale ressaltar que é necessária a criação da base de feriados (tbl_feriados).-- Cria função para calcular dias úteis entre duas datas informadasIF exists (SELECT * FROM dbo.sysobjects WHERE ID = object_id(N'[dbo].[fcnDiasUteis]'))DROP FUNCTION [dbo].[fcnDiasUteis]GOCREATE FUNCTION fcnDiasUteis (@DataInicial datetime, @DataFinal datetime)RETURNS intASBEGIN -- Cria variaveis DECLARE @Feriados int, @Retorno int, @DiasAUX int, @DataAUX datetime -- Seta primeiro dia da semana em domingo --SET DATEFIRST 7 -- Monta cursor DECLARE CursorFeriado CURSOR FOR SELECT count(*) 'Total' FROM tbl_Feriados WHERE dat_Feriado between @DataInicial + 1 AND @DataFinal AND DATEPART(dw, dat_Feriado) not in (1, 7) -- Abre cursor OPEN CursorFeriado -- Pega primeiro FETCH NEXT FROM CursorFeriado INTO @Feriados -- Seta dias úteis como 0 SET @Retorno = DateDiff(d, @DataInicial, @DataFinal) -- Seta data auxiliar para cálculos SET @DataAUX = @DataFinal -- Contabiliza dias úteis WHILE @DataInicial <= @DataAUX BEGIN -- Se for final de semana, desconsidera do total IF DATEPART(dw, @DataAUX) in (1, 7) BEGIN SET @Retorno = @Retorno - 1 END -- Subtrai um da data auxiliar SET @DataAUX = @DataAUX - 1 END -- Corrige caso data inicial seja um FDS IF DATEPART(dw, @DataInicial) in (1, 7) BEGIN SET @Retorno = @Retorno + 1 END -- Fecha cursor CLOSE CursorFeriado DEALLOCATE CursorFeriado -- Desconsidera os feriados SET @Retorno = @Retorno - @Feriados RETURN(@RETORNO)END

Compartilhar este post


Link para o post
Compartilhar em outros sites

Segue abaixo a rotina que fiz com base em outra rotina que encontrei.

 

É só passar a data inicial e a data final que ela retorna o total de dias úteis (sem sábado, domingo e feriado).

Obs.: os feriados que estão cadastrados são todos os feriados nacionais e do Rio de Janeiro. Caso você seja de outro estado é só eliminar os feriados do Rio (São Sebastião, São Jorge e Zumbi).

 

 

<?php

//================================================

// Função para calcular os dias úteis entre datas,

// excluindo sábados, domingos e feriados Nacionais e Estaduais (RJ)

//

// Parâmetros: data Inicial e data Final

// modo de passagem das datas:

// $data1=mktime(0, 0, 0, dia_inicial,mes_inicial,ano_inicial);

// $data2=mktime(0, 0, 0, dia_final,mes_final,ano_final);

// $x=calcula_dias_uteis($data1,$data2);

//

// Autor: Ney Sales

// Data: 31/05/2010

//====================================================

 

function calcula_dias_uteis($dataInicial, $dataFinal){

 

$diaInicial = date("d",$dataInicial);

$mesInicial = date("m",$dataInicial);

$anoInicial = date("Y",$dataInicial);

 

$diaFinal = date("d",$dataFinal);

$mesFinal = date("m",$dataFinal);

$anoFinal = date("Y",$dataFinal);

 

//monta array com os feriados no ano. Caso o ano anterior seja diferente do atual monta dois arrays

if ($anoInicial!=$anoFinal){

$fer1 = dias_feriados($anoInicial);

}else{

$fer1 = 0;

}

$fer2 = dias_feriados($anoFinal);

 

//calculo timestam das duas datas

$timestamp1 = mktime(0,0,0,$mesFinal,$diaFinal,$anoFinal);

$timestamp2 = mktime(4,12,0,$mesInicial,$diaInicial,$anoInicial);

 

//diminuo a uma data a outra

$segundos_diferenca = $timestamp1 - $timestamp2;

//echo $segundos_diferenca;

 

//converto segundos em dias

$dias_diferenca = $segundos_diferenca / (60 * 60 * 24);

 

//obtenho o valor absoluto dos dias (tiro o possível sinal negativo)

$dias_diferenca = abs($dias_diferenca);

 

//tiro os decimais aos dias de diferenca

$dias_diferenca = floor($dias_diferenca);

 

$totalFinalSemana=0;

$totalFeriado = 0;

for($x=0;$x<$dias_diferenca;$x++){

$diaSemana = date("w", strtotime( "+".$x." day", strtotime($anoInicial."-".$mesInicial."-".$diaInicial)));

$dia = date("d", strtotime( "+".$x." day", strtotime($anoInicial."-".$mesInicial."-".$diaInicial)));

$mes = date("m", strtotime( "+".$x." day", strtotime($anoInicial."-".$mesInicial."-".$diaInicial)));

$ano = date("Y", strtotime( "+".$x." day", strtotime($anoInicial."-".$mesInicial."-".$diaInicial)));

 

//verifica se o dia da semana é sábado ou domingo

if($diaSemana==6 || $diaSemana==0){

$totalFinalSemana ++;

}

 

//verifica se existe feriado no período selecionado

if($fer1!=0){

if($ano==$anoInicial){

foreach($fer1 as $feriado){

$mesFer=date("m",$feriado);

$diaFer=date("d",$feriado);

if($mesFer==$mes){

if($diaFer=$dia){

$totalFeriado++;

}

}

}

}

}

 

foreach($fer2 as $feriado){

$mesFer=date("m",$feriado);

$diaFer=date("d",$feriado);

if($mesFer==$mes){

if($diaFer==$dia){

$totalFeriado++;

}

}

}

}

 

//echo "<p>Dias: ".$dias_diferenca;

//echo "<p>Não Uteis: ".$totalFinalSemana;

//echo "<p>Feriados: ".$totalFeriado;

$diferenca = $dias_diferenca-($totalFinalSemana+$totalFeriado);

return $diferenca;

}

 

 

//=========================================================================

//calcula os feriados no ano

function dias_feriados($ano = null)

{

if ($ano === null)

{

$ano = intval(date('Y'));

}

 

$pascoa = easter_date($ano); // Limite de 1970 ou após 2037 da easter_date PHP consulta http://www.php.net/manual/pt_BR/function.easter-date.php

$dia_pascoa = date('j', $pascoa);

$mes_pascoa = date('n', $pascoa);

$ano_pascoa = date('Y', $pascoa);

 

$feriados = array(

// Tatas Fixas dos feriados Nacionail Basileiras

mktime(0, 0, 0, 1, 1, $ano), // Confraternização Universal - Lei nº 662, de 06/04/49

mktime(0, 0, 0, 1, 20, $ano), // São Sebastião do Rio de Janeiro

mktime(0, 0, 0, 4, 21, $ano), // Tiradentes - Lei nº 662, de 06/04/49

mktime(0, 0, 0, 4, 23, $ano), // São Jorge

mktime(0, 0, 0, 5, 1, $ano), // Dia do Trabalhador - Lei nº 662, de 06/04/49

mktime(0, 0, 0, 9, 7, $ano), // Dia da Independência - Lei nº 662, de 06/04/49

mktime(0, 0, 0, 10, 12, $ano), // N. S. Aparecida - Lei nº 6802, de 30/06/80

mktime(0, 0, 0, 11, 2, $ano), // Todos os santos - Lei nº 662, de 06/04/49

mktime(0, 0, 0, 11, 15, $ano), // Proclamação da republica - Lei nº 662, de 06/04/49

mktime(0, 0, 0, 11, 20, $ano), // Zumbi

mktime(0, 0, 0, 12, 25, $ano), // Natal - Lei nº 662, de 06/04/49

 

// These days have a date depending on easter

mktime(0, 0, 0, $mes_pascoa, $dia_pascoa - 48, $ano_pascoa),//2ºferia Carnaval

mktime(0, 0, 0, $mes_pascoa, $dia_pascoa - 47, $ano_pascoa),//3ºferia Carnaval

mktime(0, 0, 0, $mes_pascoa, $dia_pascoa - 2 , $ano_pascoa),//6ºfeira Santa

mktime(0, 0, 0, $mes_pascoa, $dia_pascoa , $ano_pascoa),//Pascoa

mktime(0, 0, 0, $mes_pascoa, $dia_pascoa + 60, $ano_pascoa),//Corpus Cirist

);

 

sort($feriados);

 

return $feriados;

}

 

?>

Compartilhar este post


Link para o post
Compartilhar em outros sites

Pessoal isso não é tão complicado como parece, podemos fazer de forma mais simples e sem usar tantas linhas de codigo, podemos usar tabela temporária , veja um exemplo:

 

 

DECLARE @CONT AS INT ,@DATA_INICIAL AS DATETIME, @DATA_FINAL AS DATETIME



SET @DATA_INICIAL = (SELECT CAST('04-04-2013' AS DATE) )
SET @DATA_FINAL = (SELECT CAST(GETDATE() AS DATE ))
SET @CONT = 0


DECLARE @TAB AS TABLE (SEMANA INT, DATA DATETIME, CONT INT )


WHILE @CONT < (SELECT DATEDIFF(DD, @DATA_INICIAL, @DATA_FINAL ))
BEGIN


INSERT INTO @TAB SELECT DATEPART(DW,(DATEADD(DD, @CONT, @DATA_INICIAL))),        DATEADD(DD, @CONT, @DATA_INICIAL), @CONT
SET @CONT = @CONT+1
END


SELECT COUNT(SEMANA) FROM @TAB WHERE SEMANA NOT IN (1,7)
Editado por Motta

Compartilhar este post


Link para o post
Compartilhar em outros sites

Olá pessoal. Estava procurando algo desse tipo na net pois enfrentava este dilema de calcular dias úteis no Oracle.
Cansado de procurar, resolvi criar uma função pra isso. Ela conta tirando os feriados locais e nacionais cadastrados na tabela e conta caso queira por exemplo considerar sábado e/ou domingo como dia útil. Este ultimo, porque eu trabalho com turmas de treinamentos e algumas delas eram faturadas pelo fornecedor também nos sábados e/ou domingos, então eu tinha que considerar como dia útil.
A tabela de feriados esta separada por estado porque como tem feriados locais também, tive que separar assim.
A função ficou assim:
create or replace FUNCTION DIAS_UTEIS(vCOD_UF INT, vDATAI IN DATE, vDATAF IN DATE, PERIODO IN INT) RETURN VARCHAR2 AS
total_dias NUMBER;
total_feriados NUMBER;
total_dias_uteis NUMBER := 0;
/*
s = dias da semana que devemos considerar
0 conta sabado e domingo
1 não conta domingo
2 não conta sabado e domingo
*/
begin
 
  /*
  CONTA A QUANTIDADE DE DIAS ENTRE AS DATAS
  SEM VERIFICAR FERIADOS, SÁBADOS E DOMINGOS
  */
  FOR CUR_ROW IN (SELECT TO_DATE(vDATAF)-TO_DATE(vDATAI) TTDIAS FROM DUAL)
    LOOP 
      total_dias:=CUR_ROW.TTDIAS;
    END LOOP;
  
  /*
  CHECA SE EXISTE ALGUM DIA ENTRE AS DATAS NA LISTA DE FERIADOS E SEPARA A CONTAGEM PARA CONSIDERAR:
  0 = CONTA SÁBADO E DOMINDO
  1 = NÃO CONTA FERIADOS DE DOMINGO
  2 = NÃO CONTA FERIADOS DE SÁBADO E DOMINGO
  
  PORQUE ISSO?
  VOCÊ PODE QUERER CONSIDERAR SÁBADO COMO DIA UTIL POR EXEMPLO.
  */
  IF PERIODO = 0  THEN
    FOR CUR_ROW IN (SELECT COUNT(DATA_FERIADO) TT_FERIADOS FROM GIP_TAB_GBL_FERIADOS WHERE DATA_FERIADO BETWEEN TO_DATE(vDATAI) AND TO_DATE(vDATAF) AND COD_UF=vCOD_UF)
      LOOP 
        total_feriados:=CUR_ROW.TT_FERIADOS;
      END LOOP;
  ELSIF PERIODO = 1 THEN 
    FOR CUR_ROW IN (SELECT SUM(CASE WHEN TO_CHAR(DATA_FERIADO,'DY') NOT IN('DOM') THEN 1 ELSE 0 END) TT_FERIADOS FROM GIP_TAB_GBL_FERIADOS WHERE DATA_FERIADO BETWEEN TO_DATE(vDATAI) AND TO_DATE(vDATAF) AND COD_UF=vCOD_UF)
      LOOP 
        total_feriados:=CUR_ROW.TT_FERIADOS;
      END LOOP;
  ELSIF PERIODO = 2 THEN 
    FOR CUR_ROW IN (SELECT SUM(CASE WHEN TO_CHAR(DATA_FERIADO,'DY') NOT IN('SÁB','DOM') THEN 1 ELSE 0 END) TT_FERIADOS FROM GIP_TAB_GBL_FERIADOS WHERE DATA_FERIADO BETWEEN TO_DATE(vDATAI) AND TO_DATE(vDATAF) AND COD_UF=vCOD_UF)
      LOOP 
        total_feriados:=CUR_ROW.TT_FERIADOS;
      END LOOP;
  END IF;
  
  
  /*
  PERCORRE DIA POR DIA SEMPRE CHECANDO SE DESEJA CONTAR OU NÃO SABADO E DOMINGO
  */
  FOR i IN 0 .. total_dias
    LOOP
      IF PERIODO = 0  THEN
        FOR CUR_ROW IN (SELECT TO_DATE(vDATAI)+i FROM DUAL)
          LOOP  
            total_dias_uteis:=total_dias_uteis+1;
          END LOOP;
      ELSIF PERIODO = 1 THEN 
        FOR CUR_ROW IN (SELECT (CASE WHEN TO_CHAR(TO_DATE(vDATAI)+i,'DY') NOT IN('DOM') THEN 1 ELSE 0 END) TT FROM DUAL)
          LOOP  
            total_dias_uteis:=total_dias_uteis++CUR_ROW.TT;
          END LOOP;
      ELSIF PERIODO = 2 THEN 
         FOR CUR_ROW IN (SELECT (CASE WHEN TO_CHAR(TO_DATE(vDATAI)+i,'DY') NOT IN('SÁB','DOM') THEN 1 ELSE 0 END) TT FROM DUAL)
          LOOP  
            total_dias_uteis:=total_dias_uteis+CUR_ROW.TT;
          END LOOP;
      END IF;
    END LOOP;
 
    total_dias:=total_dias+1;
    
    
  RETURN 'TOTAL DIAS:'||total_dias||' - TOTAL FERIADOS:'||total_feriados||' - DIAS UTEIS:'||total_dias_uteis||' - DIAS UTEIS TOTAL:'||(total_dias_uteis-total_feriados);
END;
O return dela esta como varchar apenas para testar a conta e verificar se esta fazendo certo. Para pegar o resultado final, substitua por:
RETURN (total_dias_uteis-total_feriados);
Executando um exemplo:
SELECT DIAS_UTEIS(2,TO_DATE('2015-02-01'),TO_DATE('2015-02-28'),0) FROM DUAL;
A primeira variável da função é o código do estado, no meu caso tenho 2 como GO;
A segunda é a data inicial;
A terceira é a data final;
A quarta é o indicativo para contar ou não sábado e/ou domingo conforme abaixo:
0 conta sábado e domingo
1 não conta domingo
2 não conta sábado e domingo
Este SELECT resulta em:
TOTAL DIAS:28 - TOTAL FERIADOS:2 - DIAS UTEIS:28 - DIAS UTEIS TOTAL:26
*Os dois dias de feriado é por causa do Carnaval cadastrado para os dias 16 e 17/02/2015.
SELECT DIAS_UTEIS(2,TO_DATE('2015-02-01'),TO_DATE('2015-02-28'),1) FROM DUAL;
Resultado não conta domingo:
TOTAL DIAS:28 - TOTAL FERIADOS:2 - DIAS UTEIS:24 - DIAS UTEIS TOTAL:22
SELECT DIAS_UTEIS(2,TO_DATE('2015-02-01'),TO_DATE('2015-02-28'),2) FROM DUAL;
Resultado não conta sábado e domingo:
TOTAL DIAS:28 - TOTAL FERIADOS:2 - DIAS UTEIS:20 - DIAS UTEIS TOTAL:18
Espero que ajude muita gente assim como me ajudou e se alguém quiser melhorar ou sugerir algo, fiquem a vontade.
Dúvidas, só perguntar.
Obrigado aos demais que ajudaram de forma indireta.
Tabela de feriados:
 CREATE TABLE "USER_GIP_HLG"."GIP_TAB_GBL_FERIADOS" 
   ( "COD_UF" NUMBER(*,0), 
"DIA" NUMBER(*,0), 
"DATA_FERIADO" DATE, 
"FERIADO" VARCHAR2(200 BYTE), 
"NACIONAL" NUMBER(*,0)
   ) SEGMENT CREATION IMMEDIATE 
  PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 
 NOCOMPRESS LOGGING
  STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
  PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
  BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
  TABLESPACE "TBL_BASE" ;
 
   COMMENT ON COLUMN "USER_GIP_HLG"."GIP_TAB_GBL_FERIADOS"."NACIONAL" IS '0 - NACIONAL | 1 - MUNICIPAL';

 

Compartilhar este post


Link para o post
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisar ser um membro para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar Agora

×

Informação importante

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