我正在为我的仓库创建一个日历表。我将使用它作为所有日期字段的外键。
下面显示的代码创建表并填充它。 我能够弄清楚如何找到阵亡将士纪念日(五月的最后一个星期一)和劳动节(九月的第一个星期一)。
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
我很难确定感恩节(十一月最后一个完整周的星期四)。
编辑: 根据 John Sauer
的评论进行更正感恩节是十一月的第四个星期四。 然而查了几年,发现原来也是11月最后一个完整周的星期四
我很难确定感恩节(十一月最后一个完整周的星期四)。
11 月最后一个星期六 - 2
以 11 月的最后一个星期六为例,减去两天;)
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
对于复杂的算法,有时从一组中找到匹配的日期比尝试构造一个巨大的单值公式更好。
请参阅我博客中的这篇文章了解更多详细信息:
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
日期是 11 月的星期四吗?还有不到一周的时间吗?
我们在数据库中使用一个简洁的标量值函数,我们可以调用它来确定日期是否为非工作日。我们手动添加观察假期的特殊日期。
创建函数:
CREATE FUNCTION [dbo].[NonWorkDay](@date as DATETIME)
RETURNS bit
AS
BEGIN
if @date is not null
begin
-- Weekends
if DATEPART(weekday, @date)=1 return 1 --Sunday
if DATEPART(weekday, @date)=7 return 1 --Saturday
-- JAN
if month(@date)=1 AND day(@date)=1 return 1 -- New Years Day
-- MAY
if month(@date)=5 and DATEPART(weekday, @date)=2 and day(@date)>24 and day(@date)<=31 return 1 --Memorial Day
-- JULY
if month(@date)=7 AND day(@date)=4 return 1 -- July 4th
-- SEP
if month(@date)=9 and DATEPART(weekday, @date)=2 and day(@date)<=7 return 1--Labor Day
-- NOV
if month(@date)=11 and DATEPART(weekday, @date)=5 and day(@date)>21 and day(@date)<=28 return 1--Thanksgiving
if month(@date)=11 and DATEPART(weekday, @date)=6 and day(@date)>22 and day(@date)<=29 return 1 -- Black Friday
-- DEC
if month(@date)=12 AND day(@date)=24 return 1 -- Christmas Eve
if month(@date)=12 AND day(@date)=25 return 1 -- Christmas
if month(@date)=12 AND day(@date)=31 return 1 -- NYE
-- Office Closed for Observed Holiday Dates
if month(@date)=7 AND day(@date)=5 AND year(@date)=2021 return 1 -- 4th of July Observed for 2021
if month(@date)=12 AND day(@date)=26 AND year(@date)=2022 return 1 -- Christmas Day observed for 2022
if month(@date)=1 AND day(@date)=2 AND year(@date)=2023 return 1 -- New Years Day observed for 2023
if month(@date)=7 AND day(@date)=3 AND year(@date)=2026 return 1 -- 4th of July Observed for 2026
if month(@date)=7 AND day(@date)=5 AND year(@date)=2027 return 1 -- 4th of July Observed for 2027
end
return 0
END
GO
通话功能:
IF [dbo].[NonWorkDay](Getdate())= 0 -- If (not a NonWorkDay -ie not Sat or Sun)
这应该可以解决问题:
declare @is_thanksgiving bit,
@cur_date datetime = getdate()
select @is_thanksgiving = case when datename(month, @cur_date) = 'November'
and datename(weekday, @cur_date) = 'Thursday'
and day(@cur_date) between 22 and 28
then 1 else 0 end
第四个星期四应该介于:
这与 Christian Pena 的答案非常相似,但我认为他的答案相差 1。