Numero de dias entre duas datas
- dr_gori
- Moderador
- Mensagens: 5024
- Registrado em: Seg, 03 Mai 2004 3:08 pm
- Localização: Portland, OR USA
- Contato:
Thomas F. G
Você já respondeu a dúvida de alguém hoje?
https://glufke.net/oracle/search.php?search_id=unanswered
Você já respondeu a dúvida de alguém hoje?
https://glufke.net/oracle/search.php?search_id=unanswered
Sim, é o sinal de MENOS.
data2 - data1 vai retornar o número de dias entre as duas datas.
data2 - data1 vai retornar o número de dias entre as duas datas.
- dr_gori
- Moderador
- Mensagens: 5024
- Registrado em: Seg, 03 Mai 2004 3:08 pm
- Localização: Portland, OR USA
- Contato:
Thomas F. G
Você já respondeu a dúvida de alguém hoje?
https://glufke.net/oracle/search.php?search_id=unanswered
Você já respondeu a dúvida de alguém hoje?
https://glufke.net/oracle/search.php?search_id=unanswered
Mas eu não entendo.. pra que você quer uma função pra isso?
Se você tiver 2 datas e quiser saber o número de dias entre elas, basta subtratir uma da outra.
você pode fazer uma função pra isso sim, mas é só pra confundir quem vai mexer no sistema depois.
Se você tiver 2 datas e quiser saber o número de dias entre elas, basta subtratir uma da outra.
você pode fazer uma função pra isso sim, mas é só pra confundir quem vai mexer no sistema depois.
create or replace function dias_data( d1 date, d2 date) return number
is
begin
return d2 - d1;
end;
/
- Toad
- Rank: DBA Pleno
- Mensagens: 253
- Registrado em: Sex, 18 Nov 2005 2:14 pm
- Localização: Seattle, WA
- Contato:
Matheus Gonçalves
matheus.dev
twitter.com/developer__c
matheus.dev
twitter.com/developer__c
Não sei se é essa a dúvida dele, mas acabei de me deparar com esse problema.
Tenho uma data DATA1 e uma data DATA2.
Como eu faço para calcular quantos dias úteis existem entre DATA1 e DATA2!? (Não conta fins de semana nem feriados nacionais).
Imagino que vá dar uma função enorme... alguém tem algo relacionado por aí?
Abraços!!
Obrigado!
Toad
Tenho uma data DATA1 e uma data DATA2.
Como eu faço para calcular quantos dias úteis existem entre DATA1 e DATA2!? (Não conta fins de semana nem feriados nacionais).
Imagino que vá dar uma função enorme... alguém tem algo relacionado por aí?
Abraços!!
Obrigado!
Toad
- dr_gori
- Moderador
- Mensagens: 5024
- Registrado em: Seg, 03 Mai 2004 3:08 pm
- Localização: Portland, OR USA
- Contato:
Thomas F. G
Você já respondeu a dúvida de alguém hoje?
https://glufke.net/oracle/search.php?search_id=unanswered
Você já respondeu a dúvida de alguém hoje?
https://glufke.net/oracle/search.php?search_id=unanswered
Acho que o jeito mais fácil é você criar um programa que conta quantos dias tem entre uma data e outra e faz um LOOP. Caso o dia da semana for de segunda a sexta, soma em um contador...
Eu fiz um SQL aqui que faz mais ou menos a mesma coisa. Talvez fazer uma rotina em PL/SQL seja mais rápida que esse sql.
Vamos ao exemplo:
Eu fiz um SQL aqui que faz mais ou menos a mesma coisa. Talvez fazer uma rotina em PL/SQL seja mais rápida que esse sql.
declare
vtemp number;
vdata1 date;
vdata2 date;
begin
vdata1 := to_date('03/02/2006','dd/mm/rrrr');
vdata2 := to_date('28/02/2006','dd/mm/rrrr');
select count(dat)
into vtemp
from
(
select vdata1 + rownum-1 dat
from all_tables
where rownum <= ( vdata2-vdata1)+1
)
where to_char(dat, 'd') not in (1,7);
dbms_output.put_line('Numero de dias úteis: '||vtemp);
end;
SQL> set serveroutput on
SQL> declare
2 vtemp number;
3 vdata1 date;
4 vdata2 date;
5 begin
6 vdata1 := to_date('03/02/2006','dd/mm/rrrr');
7 vdata2 := to_date('28/02/2006','dd/mm/rrrr');
8
9 select count(dat)
10 into vtemp
11 from
12 (
13 select vdata1 + rownum-1 dat
14 from all_tables
15 where rownum <= ( vdata2-vdata1)+1
16 )
17 where to_char(dat, 'd') not in (1,7);
18
19 dbms_output.put_line('Numero de dias úteis: '||vtemp);
20 end;
21 /
Numero de dias úteis: 18
PL/SQL procedure successfully completed.
SQL>
Editado pela última vez por dr_gori em Seg, 06 Fev 2006 8:39 am, em um total de 1 vez.
- Toad
- Rank: DBA Pleno
- Mensagens: 253
- Registrado em: Sex, 18 Nov 2005 2:14 pm
- Localização: Seattle, WA
- Contato:
Matheus Gonçalves
matheus.dev
twitter.com/developer__c
matheus.dev
twitter.com/developer__c
Fala Dr.
Tudo tranquilo? Obrigado desde já pela ajuda.
Tentei gerar uma função com o sql que você passou, ficou mais ou menos assim:
Mas está dando erro em "from ( select" ...
Tentei fazer via cursor também. Ficou assim:
Mas também dá erro no parênteses..... O que estou fazendo de errado?:?:
Abraços e obrigado desde já!
Matheus
Tudo tranquilo? Obrigado desde já pela ajuda.
Tentei gerar uma função com o sql que você passou, ficou mais ou menos assim:
FUNCTION DIAS_UTEIS(DATA1 IN DATA, DATA2 IN DATA) RETURN NUMBER IS
vdata1 date := to_date(DATA1,'dd/mm/rrrr');
vdata2 date := to_date(DATA2,'dd/mm/rrrr');
vtemp number;
begin
select count(dat)into vtemp
from (select vdata1 + rownum-1 dat from all_tables where rownum <= ( vdata2-vdata1)+1 )
where to_char(dat, 'd') not in (1,7);
RETURN vtemp;
end;
Tentei fazer via cursor também. Ficou assim:
FUNCTION DIAS_UTEIS(DATA1 IN DATA, DATA2 IN DATA) RETURN NUMBER IS
vdata1 date := to_date(DATA1,'dd/mm/rrrr');
vdata2 date := to_date(DATA2,'dd/mm/rrrr');
vtemp number;
cursor DATA is select count(dat)
from (
select vdata1 + rownum-1 dat
from all_tables where rownum <= ( vdata2-vdata1)+1
)
where to_char(dat, 'd') not in (1,7);
begin
OPEN DATA;
FETCH DATA INTO vtemp;
CLOSE DATA;
RETURN vtemp;
end;
Abraços e obrigado desde já!
Matheus
- dr_gori
- Moderador
- Mensagens: 5024
- Registrado em: Seg, 03 Mai 2004 3:08 pm
- Localização: Portland, OR USA
- Contato:
Thomas F. G
Você já respondeu a dúvida de alguém hoje?
https://glufke.net/oracle/search.php?search_id=unanswered
Você já respondeu a dúvida de alguém hoje?
https://glufke.net/oracle/search.php?search_id=unanswered
O problema é que você está declarando DATA1 IN DATA...
Deve ser DATE...
Faz assim:
Testando:
Deve ser DATE...
Faz assim:
create or replace FUNCTION DIAS_UTEIS( vDATA1 IN DATE, vDATA2 IN DATE) RETURN NUMBER IS
vtemp number;
begin
select count(dat)into vtemp
from (select vdata1 + rownum-1 dat from all_tables where rownum <= ( vdata2-vdata1)+1 )
where to_char(dat, 'd') not in (1,7);
RETURN vtemp;
end;
SQL> select dias_uteis(sysdate-30, sysdate) uteis from dual;
UTEIS
----------
21
SQL>
- Toad
- Rank: DBA Pleno
- Mensagens: 253
- Registrado em: Sex, 18 Nov 2005 2:14 pm
- Localização: Seattle, WA
- Contato:
Matheus Gonçalves
matheus.dev
twitter.com/developer__c
matheus.dev
twitter.com/developer__c
Incluí agora a opção para ele não contar os feriados nacionais.
Ficou assim:
Talvez usando and (to_char(dat,'dd/mm') not in (fer_01, fer_02... também funcione, mas não testei!
Obrigado e abraços!
Matheus
Ficou assim:
create or replace FUNCTION DIAS_UTEIS( vDATA1 IN DATE, vDATA2 IN DATE) RETURN NUMBER IS
vtemp number;
fer_01 varchar2(5) := '01/01';
fer_02 varchar2(5) := '14/04';
fer_03 varchar2(5) := '21/04';
fer_04 varchar2(5) := '01/05';
fer_05 varchar2(5) := '15/06';
fer_06 varchar2(5) := '07/09';
fer_07 varchar2(5) := '12/10';
fer_08 varchar2(5) := '02/11';
fer_09 varchar2(5) := '15/11';
fer_10 varchar2(5) := '25/12';
begin
select count(dat)into vtemp
from (select vdata1 + rownum-1 dat from i_os where rownum <= (vdata2-vdata1)+1 )
where to_char(dat, 'd') not in (1,7)
and (to_char(dat,'dd/mm') <> fer_01)
and (to_char(dat,'dd/mm') <> fer_02)
and (to_char(dat,'dd/mm') <> fer_03)
and (to_char(dat,'dd/mm') <> fer_04)
and (to_char(dat,'dd/mm') <> fer_05)
and (to_char(dat,'dd/mm') <> fer_06)
and (to_char(dat,'dd/mm') <> fer_07)
and (to_char(dat,'dd/mm') <> fer_08)
and (to_char(dat,'dd/mm') <> fer_09)
and (to_char(dat,'dd/mm') <> fer_10);
vtemp := vtemp - 1;
RETURN vtemp;
end;
Obrigado e abraços!
Matheus
- dr_gori
- Moderador
- Mensagens: 5024
- Registrado em: Seg, 03 Mai 2004 3:08 pm
- Localização: Portland, OR USA
- Contato:
Thomas F. G
Você já respondeu a dúvida de alguém hoje?
https://glufke.net/oracle/search.php?search_id=unanswered
Você já respondeu a dúvida de alguém hoje?
https://glufke.net/oracle/search.php?search_id=unanswered
Acho que o ideal é você criar uma tabela de feriados.
Daí basta você colocar NOT IN (select feriado from TB_FERIADOS)... saca ?
Dessa forma, você está engessando os feriados. Cada vez, terá que alterar a rotina... Também você não pode tratar feriados específicos de cada estado da forma engessada...
Com uma tabela, fica tudo bem flexivel !
Daí basta você colocar NOT IN (select feriado from TB_FERIADOS)... saca ?
Dessa forma, você está engessando os feriados. Cada vez, terá que alterar a rotina... Também você não pode tratar feriados específicos de cada estado da forma engessada...
Com uma tabela, fica tudo bem flexivel !
- Toad
- Rank: DBA Pleno
- Mensagens: 253
- Registrado em: Sex, 18 Nov 2005 2:14 pm
- Localização: Seattle, WA
- Contato:
Matheus Gonçalves
matheus.dev
twitter.com/developer__c
matheus.dev
twitter.com/developer__c
Claro... você tem razão... na verdade a idéia é só com os feriados nacionais, mas com uma tabela, e não engessado, casa exista alguma alteração e/ou adição de feriado, fica bem mais simples...
Obrigado.
Obrigado.
- Toad
- Rank: DBA Pleno
- Mensagens: 253
- Registrado em: Sex, 18 Nov 2005 2:14 pm
- Localização: Seattle, WA
- Contato:
Matheus Gonçalves
matheus.dev
twitter.com/developer__c
matheus.dev
twitter.com/developer__c
Seguindo essa linha de raciocínio, ficou assim a função:
E a tabela assim:
Agora, se for necessário alterar as datas, é só mexer na tabela e não na função!
Abraços!
create or replace FUNCTION DIAS_UTEIS( vDATA1 IN DATE, vDATA2 IN DATE) RETURN NUMBER IS
vtemp number;
begin
select count(dat)into vtemp
from (select vdata1 + rownum-1 dat from i_os where rownum <= (vdata2-vdata1)+1 )
where to_char(dat, 'd') not in (1,7)
and to_char(dat,'dd/mm') not in (select dia from i_feriado);
vtemp := vtemp - 1;
RETURN vtemp;
end;
E a tabela assim:
SQL> desc i_feriado
Name Null? Type
------------------------------- -------- ----
CODIGO NUMBER(5)
DIA VARCHAR2(5)
DESCRICAO VARCHAR2(60)
SQL> select * from i_feriado
2 /
CODIGO DIA DESCRICAO
--------- ----- ------------------------------------------------------------
1 01/01 Confraternizacao Universal
2 14/04 Paixão de Cristo
3 21/04 Tiradentes
4 01/05 Dia do Trabalho
5 15/06 Corpus Christi
6 09/07 Data Magna de SP
7 20/08 Aniversário SBC
8 07/09 Independencia
9 12/10 Nossa Senhora Aparecida
10 02/11 Finados
11 15/11 Proclamação da República
12 25/12 Natal
12 rows selected.
Abraços!
- leobbg
- Rank: Programador Júnior
- Mensagens: 22
- Registrado em: Sex, 29 Out 2004 10:25 am
- Localização: PORTO ALEGRE - RS
Leo BBG Consultor Oracle
Cara, apenas para complementar,...
É melhor incluir o ano na tabela de feriados tmb.. pois existem alguns feriados que mudam de um ano para o outro um exemplo deles é o Carnaval.
valeu!!
É melhor incluir o ano na tabela de feriados tmb.. pois existem alguns feriados que mudam de um ano para o outro um exemplo deles é o Carnaval.
valeu!!
- Toad
- Rank: DBA Pleno
- Mensagens: 253
- Registrado em: Sex, 18 Nov 2005 2:14 pm
- Localização: Seattle, WA
- Contato:
Matheus Gonçalves
matheus.dev
twitter.com/developer__c
matheus.dev
twitter.com/developer__c
É...eu não cadastrei aí, mas na minha tabela também tem os feriados dos carnavais desde 1990. Se interessar para alguém, é só pedir!
Abraços!
Abraços!
-
- Rank: Estagiário Júnior
- Mensagens: 1
- Registrado em: Qui, 17 Dez 2015 6:43 pm
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:
O return dela esta como varchar apenas para testar a conta e verificar se esta fazendo certo. Para pegar o resultado final, substitua por:
Executando um exemplo:
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:
*Os dois dias de feriado é por causa do Carnaval cadastrado para os dias 16 e 17/02/2015.
Resultado não conta domingo:
Resultado não conta sábado e domingo:
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:
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;
RETURN (total_dias_uteis-total_feriados);
SELECT DIAS_UTEIS(2,TO_DATE('2015-02-01'),TO_DATE('2015-02-28'),0) FROM DUAL;
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
SELECT DIAS_UTEIS(2,TO_DATE('2015-02-01'),TO_DATE('2015-02-28'),1) FROM DUAL;
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;
TOTAL DIAS:28 - TOTAL FERIADOS:2 - DIAS UTEIS:20 - DIAS UTEIS TOTAL:18
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';
-
- Informação
-
Quem está online
Usuários navegando neste fórum: Nenhum usuário registrado e 0 visitante