El siguiente código lo genere para que mis amigos del Nacional Monte de Piedad y tiene la lógica necesaria para generar un calendario de fechas desde 1901 hasta 2020, incluyendo los feriados obligatorios y no obligatorios de ley (Día de todos los Santos, Día de Muertos, Aniversario de la Batalla Puebla, Aniversario de la Revolución Mexicana, Natalicio de Benito Juarez, Navidad, Día de la Raza, Día de la Bandera, Día de Independencia, Día del Trabajo, Año Nuevo, Día de la Virgen de Guadalupe, Día de la Madre, Aniversario de la Constitución), semana santa (jueves santo, viernes santo, sábado santo y pascua), y el día del traslado del poder ejecutivo de ley.

El código se complica por:

  1. Desde año 2006 algunos de los feriados son fijos y otros se pasan a un lunes específico dentro del mes, por ejemplo el tercer lunes de noviembre.
  2. Los cálculos para la semana santa, son complejos.
  3. La transmisión del Poder Ejecutivo ocurre cada seis años en una fecha fija.

El código puede ser limpiado, para ser simplificado y probablemente requiere ser más comentado, NUEVA VERSION.

SET LANGUAGE Spanish;

GO

CREATE FUNCTION dbo.Pascua (@Yr as int)

RETURNS DATETIME

AS

BEGIN

—    Codigo encontrado en: http://www.tek-tips.com/faqs.cfm?fid=5075

Declare @Cent int, @I int, @J int, @K int, @Metonic int, @EMo int, @EDay int

Set @Cent=@Yr/100

Set @Metonic=@Yr % 19

Set @K=(@Cent17)/25

Set @I=(@Cent@Cent/4-(@Cent@K)/3+19*@Metonic+15) % 30

Set @I=@I-(@I/28)*(1-(@I/28)*(29/(@I+1))*((21@Metonic)/11))

Set @J=(@Yr+@Yr/4+@I+2@Cent+@Cent/4) % 7

Set @EMo=3+(@I@J+40)/44

Set @EDay=@I@J+2831*(@EMo/4)

RETURN CAST(CAST(@Yr*10000+@Emo*100+@Eday AS VARCHAR(8)) AS DATETIME);

/*This algorithm is from the work done by JM Oudin in 1940 and is accurate from year 1754 to 3400.*/

END;

GO

— Codigo para llenar fecha de dimension Fecha en Mexico.

; WITH Fechas(Fecha, DimFechaId) AS

(

SELECT CAST(‘19010101’ AS DATETIME)

    , YEAR(CAST(‘19010101’ AS DATETIME))*10000

    +MONTH(CAST(‘19010101’ AS DATETIME))*100

     +DAY(CAST(‘19010101’ AS DATETIME))

UNION ALL

    SELECT DATEADD(DAY, 1, Fecha), YEAR(DATEADD(DAY, 1, Fecha))*10000+MONTH(DATEADD(DAY, 1, Fecha))*100+DAY(DATEADD(DAY, 1, Fecha))

    FROM Fechas

    WHERE DATEADD(DAY, 1, Fecha)<‘20210101’

)

, Festividades (Festividad, Festivo, TipoFeriado, Dia, Lunes)

AS( SELECT ‘Dia de todos los Santos’ ,‘Festivo NO Obligatorio’, ‘NoAplica’,    1101, 0

UNION ALL SELECT ‘Dia de Muertos’ ,‘Festivo NO Obligatorio’, ‘NoAplica    ‘,    1102, 0

UNION ALL SELECT ‘Aniversario de la Batalla Puebla’ ,‘Festivo NO Obligatorio’, ‘NoAplica’,        505, 0

UNION ALL SELECT ‘Aniversario de la Revolución Mexicana’ ,‘Festivo Obligatorio’, ‘Pasar’,    1120, 3

    — 3er Lunes Noviembre

UNION ALL SELECT ‘Natalicio de Benito Juarez’ ,‘Festivo Obligatorio’, ‘Pasar’,        321, 3

    — 3er Lunes Marzo

UNION ALL SELECT ‘Navidad’, ‘Festivo Obligatorio’ ,‘Fijo’, 1225, 0

UNION ALL SELECT ‘Dia de la Raza’ ,‘Festivo NO Obligatorio’, ‘NoAplica’,    1012, 0

UNION ALL SELECT ‘Dia de la Bandera’ ,‘Festivo NO Obligatorio’, ‘NoAplica’, 224, 0

UNION ALL SELECT ‘Dia de Independencia’ ,‘Festivo Obligatorio’, ‘Fijo’, 916, 0

UNION ALL SELECT ‘Dia del Trabajo’, ‘Festivo Obligatorio’ ,‘Fijo’, 501, 0

UNION ALL SELECT ‘Año Nuevo’ ,‘Festivo Obligatorio’, ‘Fijo’,     101, 0

UNION ALL SELECT ‘Día de la Virgen de Guadalupe’ ,‘Festivo Obligatorio’, ‘Fijo’, 1212, 0

UNION ALL SELECT ‘Dia de la Madre’ ,‘Festivo NO Obligatorio’, ‘NoAplica’, 510, 0

UNION ALL SELECT ‘Aniversario de la Constitucion’ ,‘Festivo Obligatorio’, ‘Pasar’, 205, 1

    — Primer Lunes de Febrero

)

SELECT DimFechaId

    , Fechas.Fecha AS Fecha

    , (DimFechaId/10000)*10000+101 AS AnioId

    , CAST(Year(Fechas.Fecha) AS CHAR(4)) AS AnioNombre

    , 300*(DimFechaId/300)+1 AS TrimestreId

    , ‘Q’+CAST(DATEPART(Quarter, Fechas.Fecha) AS VARCHAR(1))

        + ‘-‘ +CAST(Year(Fechas.Fecha) AS CHAR(4)) AS TrimestreNombre

    , (DimFechaId/100)*100+1 AS MesId

    , CAST(DATENAME(Month, Fechas.Fecha) AS VARCHAR(25))+ ‘-‘

+ CAST(Year(Fechas.Fecha) AS CHAR(4)) AS MesNombre

     , YEAR(DATEADD(DAY, 1, DATEADD(DAY, DATEPART(Weekday, Fechas.Fecha), Fechas.Fecha) ))*10000

        +MONTH(DATEADD(DAY, 1, DATEADD(DAY, DATEPART(Weekday, Fechas.Fecha), Fechas.Fecha) ))*100

        +DAY(DATEADD(DAY, 1, DATEADD(DAY, DATEPART(Weekday, Fechas.Fecha), Fechas.Fecha) )) AS SemanaId

    , ‘S’+RIGHT(‘0’+CAST(DATENAME(Week, Fechas.Fecha) AS VARCHAR(25)),2)+ ‘-‘

+ CAST(Year(Fechas.Fecha) AS CHAR(4)) AS SemanaName

    , DATEPART(Weekday, Fechas.Fecha) AS DiaSemanaID

    , DATENAME(Weekday, Fechas.Fecha) AS DiaSemanaNombre

    , CASE

     WHEN DATEPART(Weekday, Fechas.Fecha) IN (6,7) THEN ‘FinSemana’

            ELSE ‘EntreSemana’

        END AS DiaEntreFinSemana

    , CASE

        WHEN YEAR(Fechas.Fecha)<1991 THEN ‘No Aplica’

        WHEN DATEPART(Weekday, Fechas.Fecha) IN (7) THEN ‘NO Hábil’

        WHEN Fechas.Fecha BETWEEN DATEADD(day, 2, dbo.Pascua(YEAR(Fechas.Fecha)))

                        AND dbo.Pascua(YEAR(Fechas.Fecha)) THEN ‘NO Hábil’

        WHEN (Fechas.DimFechaId%10000)=1201    — Primero de Diciembre

                    AND ((Fechas.DimFechaId/10000)-1994)%6=0    — 1 de Cada 6 años

                    THEN ‘NO Hábil’

        WHEN Festividades.Festivo=‘Festivo Obligatorio’

            AND (Festividades.TipoFeriado=‘Fijo’ or YEAR(Fechas.Fecha)<=2006)

— Nueva Ley Aplica del 2006 en Adelante

            THEN ‘NO Hábil’

        WHEN FLunes.Festivo=‘Festivo Obligatorio’

            AND DATEPART(Weekday, Fechas.Fecha) =1

            THEN ‘NO Hábil’

        WHEN FLunes.Festivo=‘Festivo Obligatorio’

                AND Festividades.TipoFeriado=‘Pasar’

                AND YEAR(Fechas.Fecha)>2006

            THEN ‘NO Hábil’

        ELSE ‘Hábil’

        END AS DiaHabilFeriadoCorp

    , CASE

            WHEN YEAR(Fechas.Fecha)<1991 THEN ‘No Aplica’    

            WHEN dbo.Pascua(YEAR(Fechas.Fecha))=Fechas.Fecha THEN ‘Pascua’

            WHEN Fechas.Fecha BETWEEN DATEADD(day, 1, dbo.Pascua(YEAR(Fechas.Fecha)))

                            AND DATEADD(day, 3, dbo.Pascua(YEAR(Fechas.Fecha)))

                                THEN DATENAME(Weekday, Fechas.Fecha) + ‘ Santo’

            WHEN (Fechas.DimFechaId%10000)=1201    — Primero de Diciembre

                        AND ((Fechas.DimFechaId/10000)-1994)%6=0    — 1 de Cada 6 años

                        THEN ‘Transmisión del Poder Ejecutivo Federal’

            ELSE COALESCE(Festividades.Festividad

                                        , FLunes.Festividad

                                        , ‘NO Festivo’) END AS Festividad

        , CASE

            WHEN YEAR(Fechas.Fecha)<1991 THEN ‘No Aplica’    

            WHEN Fechas.Fecha BETWEEN DATEADD(day, 2, dbo.Pascua(YEAR(Fechas.Fecha)))

                                                                                     AND dbo.Pascua(YEAR(Fechas.Fecha)) THEN ‘Festivo Obligatorio’        

            WHEN (Fechas.DimFechaId%10000)=1201    — Primero de Diciembre

                        AND ((Fechas.DimFechaId/10000)-1994)%6=0    — 1 de Cada 6 años

                                THEN ‘Festivo Obligatorio’    

            WHEN Festividades.Festivo IS NOT NULL and Festividades.TipoFeriado=‘Pasar’

                    THEN ‘Festivo Pasado’

            WHEN Festividades.Festivo IS NOT NULL

                    THEN Festividades.Festivo

            WHEN FLunes.Festivo IS NOT NULL

                    THEN ‘Lunes: Festivo Pasado’

            ELSE ‘NO Festivo’ END AS TipoFestivoFestivo

FROM Fechas

LEFT JOIN Festividades

ON (Fechas.DimFechaId % 10000)=Festividades.Dia

    AND YEAR(Fechas.Fecha)>=1990

LEFT JOIN Festividades AS FLunes

ON DATEPART(Weekday, Fechas.Fecha)=1                — Dia Lunes

        AND FLunes.TipoFeriado=‘Pasar’                — Que el Feriado sea Pasar

        AND FLunes.Dia/100=month(Fechas.Fecha)        — Que sea el mismo Mes

        AND YEAR(Fechas.Fecha)>2006

        AND DATEADD(DAY, ((8DATEPART(WEEKDAY, CAST(CAST(YEAR(Fechas.Fecha)*10000

+(FLunes.Dia/100)*100+1 AS CHAR(8)) AS SMALLDATETIME)))%7)+ ((FLunes.Lunes1)*7)

            , CAST(CAST(YEAR(Fechas.Fecha)*10000+(FLunes.Dia/100)*100+1 AS CHAR(8)) AS SMALLDATETIME))

                =Fechas.Fecha

        AND DATEPART(Weekday

            , CAST(CAST( FLunes.Dia+10000*YEAR(Fechas.Fecha) as varchar(8)) AS SMALLDATETIME))

            NOT IN (1, 6,7)

ORDER BY Fechas.Fecha

OPTION (MAXRECURSION 0)

 

Definitivamente el lenguaje SQL no fue creado para hacer este tipo de consultas!

 

Javier Loria

Javier es Mentor de SolidQ basado en Costa Rica. Él comenzó su carrera profesional en 1992, como un desarrollador de software e ingeniero de sistema. Su carrera evolucionó rápidamente hacia la formación, especialmente en el mundo XML y OLAP, con clientes de formación en diferentes lugares en América Latina. Es un arquitecto de software y ayuda a nuestros clientes en América Latina a implementar arquitecturas de Business Intelligence. Javier se convirtió en SQL Server MVP en 2001 y es un MCT, MCSE, MCSD, y MCAD. Javier fue uno de los autores de los cursos de entrenamiento Microsoft de Microsoft SQL Server 2005. Es el coautor de varios libros, incluyendo MOC2782: Diseño de bases de datos de Microsoft ® SQL Server ™ 2005, el kit de formación MCTS 70-431: implementación y mantenimiento de SQL Server 2005 y Microsoft SQL Server 2005 Database Essentials Step by Step.

Latest posts by Javier Loria (see all)