Por que eu devo ler este artigo: Com este artigo pretendo passar para vocês a forma mais completa de ter como retorno a diferença entre duas datas, por exemplo, “a quanto tempo o funcionário está trabalhando nesta empresa?” Essa função utiliza um bloco feito em PL/SQL do Oracle. Esta funcionalidade é baseada em cálculos feito entre as datas e que também permite utilizar mascaras, assim, possibilitando que você tenha o número de anos, meses, dias, minutos e horas de uma maneira geral.
Criando a função
Ao criar esse tipo de função, você estará criando um objeto de banco de dados Oracle que poderá ser acessado por qualquer usuário conectado ao banco, desde que o usuário tenha acesso a consultá-lo.
CREATE OR REPLACE
FUNCTION schema.retorna_tempo
(P_DT_INICIAL IN DATE
,P_MASC IN VARCHAR2 := Null
,P_DT_FINAL IN DATE := Null
)
RETURN VARCHAR2
IS
Type Rec_Tempo Is Record(
Qtd Integer
,str Varchar2(10) );
vIndice Integer := 0;
vMascara Varchar2(60);
vData Date;
vRetorno Varchar2(100);
vCaracter Char(01);
vOculta Boolean := False; -->> False Oculsta, true exibe
vAno Rec_Tempo; -->> Registro que irá armazenar o Ano
vMes Rec_Tempo; -->> Registro que irá armazenar o Mes
vDia Rec_Tempo; -->> Registro que irá armazenar o Dia
vHora Rec_Tempo; -->> Registro que irá armazenar a Hora
vMin Rec_Tempo; -->> Registro que irá armazenar o Minuto
BEGIN
/*A função NVL é utilizada sempre que queremos que um determinado processo seja executado sem falhas, com isso
quando encontra um parametro ou retorno da consulta com a possibilidade de ser nulo, utilizando a função para impedir
que algum erro ocorra.*/
vData := Nvl(P_DT_FINAL,Sysdate);
vMascara := Nvl( P_MASC, 'a' ); /*Estou deixando como mascará default, a de Ano*/
vAno.Qtd := TO_CHAR(vData,'YYYY') - TO_CHAR(P_DT_INICIAL,'YYYY');
IF vData - ADD_MONTHS( Trunc(P_DT_INICIAL), vAno.Qtd * 12 ) < 0 THEN
vAno.Qtd := vAno.Qtd - 1;
END IF;
vMes.Qtd := Trunc(MONTHS_BETWEEN( vData, ADD_MONTHS( P_DT_INICIAL, vAno.Qtd * 12 ) ));
vDia.Qtd := Trunc(vData - ADD_MONTHS( P_DT_INICIAL, (vAno.Qtd * 12) + vMes.Qtd ));
vHora.Qtd := Trunc((vData - (ADD_MONTHS( P_DT_INICIAL, (vAno.Qtd * 12) + vMes.Qtd ) + vDia.Qtd))*24);
vMin.Qtd := Trunc((vData - (ADD_MONTHS( P_DT_INICIAL, (vAno.Qtd * 12) + vMes.Qtd ) + vDia.Qtd))*24*60 - (vHora.Qtd*60));
If vAno.Qtd > 1 Then
vAno.str := 'Anos';
Else
vAno.str := 'Ano';
End If;
If vMes.Qtd > 1 Then
vMes.str := 'Meses';
Else
vMes.str:= 'Mês';
End If;
If vDia.Qtd > 1 Then
vDia.str:= 'Dias';
Else
vDia.str:= 'Dia';
End If;
If vHora.Qtd > 1 Then
vHora.str:= 'Horas';
Else
vHora.str:= 'Hora';
End If;
If vMin.Qtd > 1 Then
vMin.str:= 'Minutos';
Else
vMin.str:= 'Minuto';
End If;
vCaracter := Substr( vMascara, 1, 1 ); -->> Retorna o primeiro caracter da mascara
If vCaracter = '#' Then -->> O primeiro caracter sendo "#" indica que deverá inibir as informações zeradas
vOculta := True;
vIndice := 2;
vCaracter := Substr( vMascara, 2, 1 );
If vCaracter Is Null Then -->> No caso da máscara ter apenas o caracter "#" então a função retornará Null
Return Null;
End If;
Else
vIndice := 1;
End If;
Loop
If vCaracter = '"' Then
Loop
vIndice := vIndice + 1;
vCaracter := Substr( vMascara, vIndice, 1 );
Exit When vCaracter = '"' or vCaracter Is Null;
vRetorno := vRetorno || vCaracter;
End Loop;
Else
If vCaracter = 'a' Then -->> Retorno da informação em forma numerica de Anos
If vAno.Qtd > 0 or Not vOculta Then
vRetorno := vRetorno || vAno.Qtd;
End If;
Elsif vCaracter = 'A' Then -->> Retorno da informação em forma de texto de Anos
If vAno.Qtd > 0 or Not vOculta Then
vRetorno := vRetorno || vAno.Str;
End If;
Elsif vCaracter = 'm' -->> Retorno da informação em forma numerica de Mês
and Nvl(Substr(vMascara,vIndice+1,1),'.') <> 'i' Then -->> Diferencia a mascara do mês e dos minutos
If vMes.Qtd > 0 or Not vOculta Then
vRetorno := vRetorno || vMes.Qtd;
End If;
Elsif vCaracter = 'M' -->> Retorno da informação em forma de texto do Mês
and Nvl(Substr(vMascara,vIndice+1,1),'.') <> 'I' Then -->> Diferencia a mascara do mês e dos minutos
If vMes.Qtd > 0 or Not vOculta Then
vRetorno := vRetorno || vMes.Str;
End If;
Elsif vCaracter = 'd' Then -->> Retorno da informação em forma numerica de Dias
If vDia.Qtd > 0 or Not vOculta Then
vRetorno := vRetorno || vDia.Qtd;
End If;
Elsif vCaracter = 'D' Then --->> Retorno da informação em forma de texto de Dias
If vDia.Qtd > 0 or Not vOculta Then
vRetorno := vRetorno || vDia.Str;
End If;
Elsif vCaracter = 'h' Then --->> Retorno da informação em forma numerica de Horas
If vHora.Qtd > 0 or Not vOculta Then
vRetorno := vRetorno || vHora.Qtd;
End If;
Elsif vCaracter = 'H' Then -->> Retorno da informação em forma de texto de Horas
If vHora.Qtd > 0 or Not vOculta Then
vRetorno := vRetorno || vHora.Str;
End If;
Elsif vCaracter = 'm' -->> Retorno da informação em forma numerica de Minutos
and Nvl(Substr(vMascara,vIndice+1,1),'.') = 'i' Then -->> Diferencia a mascara
do mês e dos minutos
If vMin.Qtd > 0 or Not vOculta Then
vRetorno := vRetorno || vMin.Qtd;
End If;
vIndice := vIndice + 1;
Elsif vCaracter = 'M' -->> Retorno da informação em forma de texto de Minutos
and Nvl(Substr(vMascara,vIndice+1,1),'.') = 'I' Then -->> Diferencia a mascara
do mês e dos minutos
If vMin.Qtd > 0 or Not vOculta Then
vRetorno := vRetorno || vMin.Str;
End If;
vIndice := vIndice + 1;
Elsif vCaracter = 'x' Then
If vAno.Qtd >= 2 Then
vRetorno := vRetorno || vAno.Qtd;
Elsif vAno.Qtd = 1 or vMes.Qtd >= 2 Then
vRetorno := vRetorno || ((vAno.Qtd*12)+vMes.Qtd);
Elsif vMes.Qtd = 1 or vDia.Qtd >= 2 Then
vRetorno := vRetorno || ( Trunc( vData ) - Trunc( P_DT_INICIAL ) );
Elsif vOculta Then
vRetorno := vRetorno;
Elsif vDia.Qtd = 1 or vHora.Qtd >= 2 Then
vRetorno := vRetorno || ( vDia.Qtd*24 + vHora.Qtd );
Elsif vHora.Qtd = 1 and vMin.Qtd >= 2 Then
vRetorno := vRetorno || ( vHora.Qtd*60 + vMin.Qtd );
End If;
Elsif vCaracter = 'X' Then
If vAno.Qtd >= 2 Then
vRetorno := vRetorno || vAno.Str;
Elsif vAno.Qtd = 1 or vMes.Qtd >= 2 Then
vRetorno := vRetorno || 'Meses';
Elsif vMes.Qtd = 1 or vDia.Qtd >= 2 Then
vRetorno := vRetorno || 'Dias';
Elsif vOculta Then
vRetorno := vRetorno;
Elsif vDia.Qtd = 1 or vHora.Qtd >= 2 Then
vRetorno := vRetorno || 'Horas';
Elsif vHora.Qtd = 1 and vMin.Qtd >= 2 Then
vRetorno := vRetorno || 'Minutos';
End If;
Else
vRetorno := vRetorno || vCaracter;
End If;
End If;
vIndice := vIndice + 1;
vCaracter := Substr( vMascara, vIndice, 1 );
Exit When vCaracter Is Null;
End Loop;
Return vRetorno;
END retorna_tempo;
/
Utilizando a função
Ao abrir uma ferramenta de consulta acessando o banco de dados Oracle, por exemplo, o SQL*PLUS, você vai obter o seguinte retorno.
SQL> SELECT RETORNA_TEMPO(TO_DATE('01/01/2006 08:59','DD/MM/YYYY HH24:MI'), 'aA mM dD hH miMI',TO_DATE('28/02/2007 15:27','DD/MM/YYYY HH24:MI')) FROM DUAL
2 /
RETORNA_TEMPO(TO_DATE('01/01/200608:59','DD/MM/YYYYHH24:MI'),'AAMMDDHHMIMI',TO_DATE('28/02/200715:27','DD
----------------------------------------------------------------------------------------------------
1Ano 1Mês 27Dias 6Horas 28Minutos
Fiz um comparativo, do inicio do ano de 2006 às 08:59 até 28/02/2007 às 15:27, com isso, obtemos 1 Ano, 1 Mês, 27 Dias, 6 Horas e 28 Minutos. Essa função poderá ser utilizada para qualquer tipo de comparativo de datas.