2009-07-29 10 views
5

Estoy creando una tabla de calendario para mi almacén. Utilizaré esto como una clave foránea para todos los campos de fecha.Día del Trabajo vs. Acción de Gracias

El código que se muestra a continuación crea la tabla y la rellena. Pude averiguar cómo encontrar Memorial Day (último lunes de mayo) y Labor Day (primer lunes de septiembre).

SET NOCOUNT ON 

DROP Table dbo.Calendar 
GO 
Create Table dbo.Calendar 
(
    CalendarId    Integer NOT NULL, 
    DateValue    Date NOT NULL, 
    DayNumberOfWeek   Integer NOT NULL, 
    NameOfDay    VarChar (10) NOT NULL, 
    NameOfMonth    VarChar (10) NOT NULL, 
    WeekOfYear    Integer NOT NULL, 
    JulianDay    Integer NOT NULL, 
    USAIsBankHoliday  Bit  NOT NULL, 
    USADayName    VarChar (100) NULL, 
) 
ALTER TABLE dbo.Calendar ADD CONSTRAINT 
    DF_Calendar_USAIsBankHoliday DEFAULT 0 FOR USAIsBankHoliday 
GO 
ALTER TABLE dbo.Calendar ADD CONSTRAINT 
    DF_Calendar_USADayName DEFAULT '' FOR USADayName 
GO 

Declare @StartDate DateTime = '01/01/2000' 
Declare @EndDate DateTime = '01/01/2020' 

While @StartDate < @EndDate 
Begin 
    INSERT INTO dbo.Calendar 
    (
     CalendarId, 
     DateValue, 
     WeekOfYear, 
     DayNumberOfWeek, 
     NameOfDay, 
     NameOfMonth, 
     JulianDay 
    ) 
    Values 
    (
     YEAR (@StartDate) * 10000 + MONTH (@StartDate) * 100 + Day (@StartDate), --CalendarId 
     @StartDate,     -- DateValue 
     DATEPART (ww, @StartDate), -- WeekOfYear 
     DATEPART (dw, @StartDate), -- DayNumberOfWeek 
     DATENAME (dw, @StartDate), -- NameOfDay 
     DATENAME (M, @StartDate), -- NameOfMonth 
     DATEPART (dy, @StartDate) -- JulianDay 
    ) 

    Set @StartDate += 1 
End 

--=========================== Weekends 
-- saturday and sunday 
UPDATE dbo.Calendar SET USAIsBankHoliday = 1, USADayName += 'Weekend, ' WHERE DayNumberOfWeek IN (1, 7) 


--=========================== Bank Holidays 
-- new years day 
UPDATE dbo.Calendar SET USAIsBankHoliday = 1, USADayName += 'New Year''s Day, ' WHERE (CalendarId % 2000) IN (101) 

-- memorial day (last Monday in May) 
UPDATE dbo.Calendar 
SET USAIsBankHoliday = 1, 
    USADayName += 'Memorial Day, ' 
WHERE 1=1 
AND CalendarId IN 
    (
     SELECT MAX (CalendarId) 
     FROM dbo.Calendar 
     WHERE MONTH (DateValue) = 5 
     AND DATEPART (DW, DateValue)=2 
     GROUP BY YEAR (datevalue) 
    ) 

-- independence day 
UPDATE dbo.Calendar SET USAIsBankHoliday = 1, USADayName += 'Independence Day, ' WHERE (CalendarId % 2000) IN (704) 

-- labor day (first Monday in September) 
UPDATE dbo.Calendar 
SET USAIsBankHoliday = 1, 
    USADayName += 'Labor Day, ' 
WHERE 1=1 
AND CalendarId IN 
    (
     SELECT MIN (CalendarId) 
     FROM dbo.Calendar 
     WHERE MONTH (DateValue) = 9 
     AND DATEPART (DW, DateValue)=2 
     GROUP BY YEAR (datevalue) 
    ) 

-- thanksgiving day (fourth Thursday in November) 
UPDATE dbo.Calendar 
SET USAIsBankHoliday = 1, 
    USADayName += 'Thanksgiving Day, ' 
WHERE 1=1 
AND CalendarId IN 
    (
     SELECT Max (CalendarId) 
     FROM dbo.Calendar 
     WHERE MONTH (DateValue) = 11 
     AND DATEPART (DW, DateValue)=5 
     GROUP BY YEAR (datevalue) 
    ) 

-- christmas 
UPDATE dbo.Calendar SET USAIsBankHoliday = 1, USADayName += 'Christmas Day, ' WHERE (CalendarId % 2000) IN (1225) 

--=========================== Other named days 
-- new years eve 
UPDATE dbo.Calendar SET USADayName += 'New Year''s Eve, ' WHERE (CalendarId % 2000) IN (1231) 

-- christmas eve 
UPDATE dbo.Calendar SET USADayName += 'Christmas Eve, ' WHERE (CalendarId % 2000) IN (1224) 

-- boxing day 
UPDATE dbo.Calendar SET USADayName += 'Boxing Day, ' WHERE (CalendarId % 2000) IN (1226) 

--=========================== Remove trailing comma 
UPDATE dbo.Calendar SET USADayName = SubString (USADayName, 1, LEN (USADayName) -1) WHERE LEN (USADayName) > 2 

SELECT * FROM dbo.Calendar 

Stumped en averiguar el día de Acción de Gracias (jueves de la última semana de noviembre).

Editar: corrección basado en comentario de John Sauer

de Acción de Gracias es el cuarto jueves de noviembre. Sin embargo, al verificar varios años, me parece que también ha sido el jueves de la última semana completa de Nov.

+0

Déjalo. Hace feliz a los pavos – balpha

+2

El comienzo del Ramadán también es un desafío. – Smandoli

+0

Y luego, está el Viernes Santo y la Pascua ... – RobH

Respuesta

16

Estoy confundido al descubrir el día de Acción de Gracias (jueves de la última semana COMPLETA de noviembre)

último sábado de noviembre - 2 de

6

Tome el último sábado de noviembre, y restar dos días;)

3
WITH cal AS 
     (
     SELECT CAST('2009-30-11' AS DATETIME) AS cdate 
     UNION ALL 
     SELECT DATEADD(day, -1, cdate) 
     FROM cal 
     WHERE cdate >= '2009-01-11' 
     ) 
SELECT TOP 1 DATEADD(day, -2, cdate) 
FROM cal 
WHERE DATEPART(weekday, cdate) = 6 

Para los algoritmos complejos, a veces es mejor encontrar una fecha coincidente desde un conjunto que intenta construir una enorme fórmula de valor único.

Lee este artículo en mi blog para más detalles:

1
declare @thedate datetime 
set @thedate = '11/24/2011' 

select 1 
where datepart(dw, @thedate) = 5 and datepart(m, @thedate) = 11 AND (datepart(dd, @thedate) - 21) between 0 and 6 

es la fecha en un jueves de noviembre y es allí menos de una semana restante.

Cuestiones relacionadas