Mostrando entradas con la etiqueta Calculo. Mostrar todas las entradas
Mostrando entradas con la etiqueta Calculo. Mostrar todas las entradas

lunes, 28 de diciembre de 2015

Calculo de días festivos para Colombia

El siguiente post tiene como fin, publicar las funciones necesarias para calcular los días festivos en Colombia. Esta desarrollado en T-SQL compatible con Sql Server 2008 o superior.

Está compuesto por 5 funciones de las cuales tres son para acciones auxiliares y las dos restantes permiten listar los festivos de un año determinado o verificar si una fecha es festivo.

Espero sea de utilidad.

1. Función que nos permite crear una fecha a partir del día, mes y año. Para evitar problemas con la configuración regional.

DROP FUNCTION F_CREAR_FECHA
GO
CREATE FUNCTION F_CREAR_FECHA(@ANIO INT, @MES INT, @DIA INT)
RETURNS DATE
AS
BEGIN
 RETURN DATEADD(mm, (@ANIO - 1900) * 12 + @MES - 1 , @DIA - 1)
END
2. Función que a partir de una fecha obtiene el siguiente lunes.


DROP FUNCTION F_OBTENER_SIGUIENTE_LUNES
GO
CREATE FUNCTION F_OBTENER_SIGUIENTE_LUNES(@FECHA DATE)
RETURNS DATE
AS
BEGIN
 DECLARE @LUNES INT = 1
 IF @@DATEFIRST = 7 
 BEGIN 
  SET @LUNES = 2
 END
 IF @@DATEFIRST = 1 
 BEGIN 
  SET @LUNES = 1
 END
 IF @@DATEFIRST = 2 
 BEGIN 
  SET @LUNES = 7
 END
 IF @@DATEFIRST = 3 
 BEGIN 
  SET @LUNES = 6
 END 
 IF @@DATEFIRST = 4 
 BEGIN 
  SET @LUNES = 5
 END   
 IF @@DATEFIRST = 5 
 BEGIN 
  SET @LUNES = 4
 END    
 IF @@DATEFIRST = 6
 BEGIN 
  SET @LUNES = 3
 END     
 DECLARE @FECHA_DEVOLVER  DATE
 IF DATEPART(DW, @FECHA) = @LUNES
 BEGIN
  SET @FECHA_DEVOLVER = @FECHA
 END
 ELSE
 BEGIN
  SET @FECHA_DEVOLVER = DATEADD([day], ((DATEDIFF([day], '19000101', @FECHA) / 7) * 7) + 7, '19000101');          
 END 
 RETURN @FECHA_DEVOLVER
END
3. Función que calcula el domingo de pascua para un año en particular.
DROP FUNCTION F_CALCULA_DOMINGO_PASCUA
GO
CREATE FUNCTION F_CALCULA_DOMINGO_PASCUA(@A_ANO INT)
RETURNS DATE
AS
BEGIN
 DECLARE @M  INT = 25
 DECLARE @N  INT = 5
 DECLARE @A  INT
 DECLARE @B  INT 
 DECLARE @C  INT 
 DECLARE @D  INT 
 DECLARE @E  INT 
 DECLARE @DIA INT
 DECLARE @MES INT
 
 IF  (@A_ANO >= 1583 AND @A_ANO <= 1699)  
 BEGIN
   SET @M = 22
   SET @N = 2
 END 
 ELSE IF (@A_ANO >= 1700 AND @A_ANO <= 1799)  
 BEGIN 
  SET @M = 23
  SET @N = 3 
 END
 ELSE IF (@A_ANO >= 1800 AND @A_ANO <= 1899)  
 BEGIN
  SET @M = 23
  SET @N = 4 
 END
 ELSE IF (@A_ANO >= 1900 AND @A_ANO <= 2099)  
 BEGIN
  SET @M = 24
  SET @N = 5 
 END
 ELSE IF (@A_ANO >= 2100 AND @A_ANO <= 2199)  
 BEGIN 
  SET @M = 24
  SET @N = 6; 
 END 
 ELSE IF (@A_ANO >= 2200 AND @A_ANO <= 2299)  
 BEGIN
  SET @M = 25
  SET @N = 0
 END  
 
 SET @A = @A_ANO % 19
 SET @B = @A_ANO % 4
 SET @C = @A_ANO % 7
 SET @D = (19 * @A + @M) % 30;
 SET @E = (2 * @B + 4 * @C + 6 * @D + @N) % 7; 

 
 IF (@D + @E < 10) 
 BEGIN
  SET @DIA = @D + @E + 22
  SET @MES = 3
 END
 ELSE 
 BEGIN 
  SET @DIA = @D + @E - 9
  SET @MES = 4
 END
 
 
 IF (@DIA = 26 AND @MES = 4)
 BEGIN 
  SET @DIA = 19
 END
 IF (@DIA = 25 AND @MES = 4 AND @D = 28 AND @E = 6 AND @A > 10)
 BEGIN
  SET @DIA = 18
 END
  
 RETURN dbo.F_CREAR_FECHA(@A_ANO, @MES, @DIA);
END

4. Función Recibe un año y retorna el listado de los festivos para ese año.
DROP FUNCTION F_LISTA_FESTIVOS
GO
CREATE FUNCTION F_LISTA_FESTIVOS(@ANIO INT)
 RETURNS @ListaFestivos TABLE(FechaFestivo DATE, Descripcion VARCHAR(50))
AS
BEGIN
 DECLARE @PASCUA DATE = dbo.F_CALCULA_DOMINGO_PASCUA(@ANIO)
 DECLARE @ES_FESTIVO BIT = 0
 
 
 -- Festivos Fecha Fija 
   INSERT INTO @ListaFestivos VALUES(dbo.F_CREAR_FECHA(@ANIO, 1, 1), 'Año Nuevo')
   INSERT INTO @ListaFestivos VALUES(dbo.F_CREAR_FECHA(@ANIO, 5, 1), 'Día del Trabajo')
   INSERT INTO @ListaFestivos VALUES(dbo.F_CREAR_FECHA(@ANIO, 7, 20), 'Grito de la Independencia')
   INSERT INTO @ListaFestivos VALUES(dbo.F_CREAR_FECHA(@ANIO, 8, 7), 'Batalla de Boyacá')   
   INSERT INTO @ListaFestivos VALUES(dbo.F_CREAR_FECHA(@ANIO, 12, 8), 'Inmaculada Concepción')      
   INSERT INTO @ListaFestivos VALUES(dbo.F_CREAR_FECHA(@ANIO, 12, 25), 'Navidad') 
 -- Festivos Siguiente Lunes
   INSERT INTO @ListaFestivos VALUES(dbo.F_OBTENER_SIGUIENTE_LUNES(dbo.F_CREAR_FECHA(@ANIO, 1, 6)), 'Epifanía (Reyes Magos)')
   INSERT INTO @ListaFestivos VALUES(dbo.F_OBTENER_SIGUIENTE_LUNES(dbo.F_CREAR_FECHA(@ANIO, 3, 19)), 'San José esposo de la virgen María')   
   INSERT INTO @ListaFestivos VALUES(dbo.F_OBTENER_SIGUIENTE_LUNES(dbo.F_CREAR_FECHA(@ANIO, 6, 29)), 'San Pedro y San Pablo')      
   INSERT INTO @ListaFestivos VALUES(dbo.F_OBTENER_SIGUIENTE_LUNES(dbo.F_CREAR_FECHA(@ANIO, 8, 15)), 'Asunción de la Virgen')         
   INSERT INTO @ListaFestivos VALUES(dbo.F_OBTENER_SIGUIENTE_LUNES(dbo.F_CREAR_FECHA(@ANIO, 10, 12)), 'Día de la Raza')            
   INSERT INTO @ListaFestivos VALUES(dbo.F_OBTENER_SIGUIENTE_LUNES(dbo.F_CREAR_FECHA(@ANIO, 11, 1)), 'Todos los Santos')               
   INSERT INTO @ListaFestivos VALUES(dbo.F_OBTENER_SIGUIENTE_LUNES(dbo.F_CREAR_FECHA(@ANIO, 11, 11)), 'Independencia de Cartagena')                  
 -- Festivos Dependientes de la pascua
   INSERT INTO @ListaFestivos VALUES(DATEADD(DAY,-7,@PASCUA), 'Domingo De Ramos')                  
   INSERT INTO @ListaFestivos VALUES(DATEADD(DAY,-3,@PASCUA), 'Jueves Santo')                     
   INSERT INTO @ListaFestivos VALUES(DATEADD(DAY,-2,@PASCUA), 'Viernes Santo')                        
   INSERT INTO @ListaFestivos VALUES(@PASCUA, 'Domingo De Pascua')                           
   INSERT INTO @ListaFestivos VALUES(DATEADD(DAY,43,@PASCUA), 'Ascensión de Jesús') 
   INSERT INTO @ListaFestivos VALUES(DATEADD(DAY,64,@PASCUA), 'Corpus Christi')    
   INSERT INTO @ListaFestivos VALUES(DATEADD(DAY,71,@PASCUA), 'Sagrado Corazón de Jesús')       

 RETURN;
END
5.Función Recibe una fecha y retorna un Booleano indicando si es festivo o no
DROP FUNCTION F_CALCULA_ES_FESTIVO
GO
CREATE FUNCTION F_CALCULA_ES_FESTIVO(@FECHA DATE)
RETURNS BIT
AS
BEGIN
 DECLARE @ES_FESTIVO BIT = 0
 IF EXISTS (SELECT * FROM dbo.F_LISTA_FESTIVOS(YEAR(@FECHA)) WHERE FechaFestivo = @FECHA) 
 BEGIN
  SET @ES_FESTIVO = 1
 END
 RETURN (@ES_FESTIVO);
END
Por último la manera de verificar las funciones:


SELECT dbo.F_CALCULA_ES_FESTIVO(CONVERT(DATE, '01/01/2016')) EsFestivo
SELECT * FROM dbo.F_LISTA_FESTIVOS(2016) ORDER BY FechaFestivo

Y el resultado de las consultas seria el siguiente:



martes, 28 de junio de 2011

Obtener la diferencia en días, meses y años entre dos fechas.

Un problema frecuente es obtener la diferencia en días, meses y años entre dos fechas, el siguiente método realizado en C# puede brindar una ayuda. este método es la adaptación en español de un trozo de código que ya se encuentra en linea.


    public String DateDifference(DateTime pFechaUno, DateTime pFechaDos)
    {
        try
        {
            int[] vDiasMes = new int[12] { 31, -1, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

            DateTime vFechaOrigen;
            DateTime vFechaDestino;
            int vAnio;
            int vMes;
            int vDia;
            int vIncremento;

            //Determinamos cual es la fecha menor
            if (pFechaUno > pFechaDos)
            {
                vFechaOrigen = pFechaDos;
                vFechaDestino = pFechaUno;
            }
            else
            {
                vFechaOrigen = pFechaUno;
                vFechaDestino = pFechaDos;
            }

            // Calculamos los dias
            vIncremento = 0;

            if (vFechaOrigen.Day > vFechaDestino.Day)
            {
                vIncremento = vDiasMes[vFechaOrigen.Month - 1];

            }
            if (vIncremento == -1)
            {
                if (DateTime.IsLeapYear(vFechaOrigen.Year))
                {
                    // Para los años bisiestos
                    vIncremento = 29;
                }
                else
                {
                    vIncremento = 28;
                }
            }
            if (vIncremento != 0)
            {
                vDia = (vFechaDestino.Day + vIncremento) - vFechaOrigen.Day;
                vIncremento = 1;
            }
            else
            {
                vDia = vFechaDestino.Day - vFechaOrigen.Day;
            }

            //Calculamos los meses
            if ((vFechaOrigen.Month + vIncremento) > vFechaDestino.Month)
            {
                vMes = (vFechaDestino.Month + 12) - (vFechaOrigen.Month + vIncremento);
                vIncremento = 1;
            }
            else
            {
                vMes = (vFechaDestino.Month) - (vFechaOrigen.Month + vIncremento);
                vIncremento = 0;
            }
            //Calculamos los años
            vAnio = vFechaDestino.Year - (vFechaOrigen.Year + vIncremento);
            return vAnio + " Año(s), " + vMes + " mes(es), " + vDia + " día(s)";
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }