#realJSOP
Вот обещанный код. На моем сервере БД этот код живет в Reference_Tables
база данных. Изменить USE
утверждение, отражающее вашу собственную парадигму.
Во-первых, это скалярная функция Ишолидея. Если вам не нужны федеральные праздники, вы можете пропустить это, но если вам это действительно нужно, вы должны добавить эту функцию *перед добавлением сохраненного proc ниже.
USE [Reference_Tables]
GO
/****** Object: UserDefinedFunction [dbo].[fn_IsHoliday] Script Date: 01/18/2017 10:39:07 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- This function returns a bit value of 1 if the specified date is a federal
-- holiday, or a 0 if it isn't a holiday.
CREATE FUNCTION [dbo].[fn_IsHoliday]
(
@date date
)
RETURNS bit
AS
BEGIN
DECLARE @year int = DATEPART(YEAR, @date);
DECLARE @month int = DATEPART(MONTH,@date);
DECLARE @day int = DATEPART(DAY, @date);
DECLARE @dayName varchar(12) = DATENAME(DW, @date );
DECLARE @nthWeekDay int = ceiling(@day / 7.0);
DECLARE @isThursday bit = CASE WHEN @dayName LIKE 'Thursday' THEN 1 ELSE 0 END;
DECLARE @isFriday bit = CASE WHEN @dayName LIKE 'Friday' THEN 1 ELSE 0 END;
DECLARE @isSaturday bit = CASE WHEN @dayName LIKE 'Saturday' THEN 1 ELSE 0 END;
DECLARE @isSunday bit = CASE WHEN @dayName LIKE 'Sunday' THEN 1 ELSE 0 END;
DECLARE @isMonday bit = CASE WHEN @dayName LIKE 'Monday' THEN 1 ELSE 0 END;
DECLARE @isWeekend bit = CASE WHEN @isSaturday = 1 OR @isSunday = 1 THEN 1 ELSE 0 END;
---- New Years Day
if (@month = 12 AND @day = 31 AND @isFriday=1) return 1;
if (@month = 1 AND @day = 1 AND @isWeekend=0) return 1;
if (@month = 1 AND @day = 2 AND @isMonday=1) return 1;
---- MLK day
if (@month = 1 AND @isMonday = 1 AND @nthWeekDay = 3) return 1;
------ President’s Day ( 3rd Monday in February )
if (@month = 2 AND @isMonday = 1 AND @nthWeekDay = 3) return 1;
------ Memorial Day ( Last Monday in May )
if (@month = 5 AND @isMonday = 1 AND DATEPART(MONTH, DATEADD(DAY, 7, @Date)) = 6) return 1;
------ Independence Day ( July 4 )
if (@month = 7 AND @day = 3 AND @isFriday = 1) return 1;
if (@month = 7 AND @day = 4 AND @isWeekend = 0) return 1;
if (@month = 7 AND @day = 5 AND @isMonday = 1) return 1;
------ Labor Day ( 1st Monday in September )
if (@month = 9 AND @isMonday = 1 AND @nthWeekDay = 1) return 1;
------ Columbus Day ( 2nd Monday in October )
if (@month = 10 AND @isMonday = 1 AND @nthWeekDay = 2) return 1;
------ Veteran’s Day ( November 11 )
if (@month = 11 AND @day = 10 AND @isFriday = 1) return 1;
if (@month = 11 AND @day = 11 AND @isWeekend = 0) return 1;
if (@month = 11 AND @day = 12 AND @isMonday = 1) return 1;
------ Thanksgiving Day ( 4th Thursday in November )
if (@month = 11 AND @isThursday = 1 AND @nthWeekDay = 4) return 1;
------ Christmas Day ( December 25 )
if (@month = 12 AND @day = 24 AND @isFriday = 1) return 1;
if (@month = 12 AND @day = 25 AND @isWeekend = 0) return 1;
if (@month = 12 AND @day = 25 AND @isMonday = 1) return 1;
return 0;
END
GO
Эта хранимая процедура возвращает таблицу дат на основе указанного диапазона дат (при желании диапазон дат может быть одним днем).
USE [Reference_Tables]
GO
/****** Object: StoredProcedure [dbo].[sp_GetCalendar] Script Date: 01/18/2017 10:38:19 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[sp_GetCalendar]
@startDate DATE, -- the start of the date range
@endDate DATE -- the end of the date range
AS
BEGIN
SET NOCOUNT ON;
-- sanity check - if the start date is not earlier than or equal to the
-- end date, switch them around
if (@startDate > @endDate)
BEGIN
DECLARE @temp date = @startDate;
SET @startDate = @endDate;
SET @endDate = @temp;
END
;WITH n AS
(
SELECT TOP (DATEDIFF(DAY, @startDate, @endDate) + 1) n = ROW_NUMBER() OVER (ORDER BY [object_id])
FROM sys.all_objects
)
SELECT DATEADD(DAY, n-1, @startDate) AS CalendarDate
,DATEPART(YEAR, DATEADD(DAY, n-1, @startDate)) AS CalendarYear
,DATEPART(MONTH, DATEADD(DAY, n-1, @startDate)) AS CalendarMonth
,DATEPART(QUARTER, DATEADD(DAY, n-1, @startDate)) AS CalendarQuarter
,DATEPART(DAYOFYEAR, DATEADD(DAY, n-1, @startDate)) As CalendarJulianDay
,DATEADD(MONTH, 3, DATEADD(DAY, n-1, @startDate)) AS FiscalDate
,DATEPART(YEAR, DATEADD(MONTH, 3, DATEADD(DAY, n-1, @startDate))) AS FiscalYear
,DATEPART(MONTH, DATEADD(MONTH, 3, DATEADD(DAY, n-1, @startDate))) AS FiscalMonth
,DATEPART(QUARTER, DATEADD(MONTH, 3, DATEADD(DAY, n-1, @startDate))) AS FiscalQuarter
,DATEPART(DAYOFYEAR, DATEADD(MONTH, 3, DATEADD(DAY, n-1, @startDate))) As FiscalJulianDay
,DATENAME(MONTH, DATEADD(DAY, n-1, @startDate)) AS [MonthName]
,DATEPART(DAY, DATEADD(DAY, n-1, @startDate)) AS [DayOfMonth]
,DATEPART(WEEKDAY, DATEADD(DAY, n-1, @startDate)) AS WeekDayNumber
,DATENAME(WEEKDAY, DATEADD(DAY, n-1, @startDate)) AS WeekDayName
,ceiling(DATEPART(DAY, DATEADD(DAY, n-1, @startDate)) / 7.0) As NthWeekday
-- if you didn't need the IsHoliday function, simply comment out
-- the following line
,dbo.fn_IsHoliday(DATEADD(DAY, n-1, @startDate)) AS IsHoliday
FROM n;
END
GO
Чтобы получить N-ю неделю (в месяце), на которую приходится дата, вы можете использовать возвращенную
NthWeekday
колонка.