我正在开发一个创建事件的日历系统。我需要能够将任何事件(在一天内发生)“前滚”到用户指定的月/年。
例如,2013 年 3 月 4 日是星期一。我需要能够根据给定的月份/年份确定相应的日期 - 基于工作日及其在月份中的位置。因此,在此示例中,4 月的对应日期为 4 月 1 日,即星期一。
另一个例子:2013 年 3 月 13 日是星期三,所以 5 月的对应日期是 5 月 8 日。
如果不是因为用户提供的月/年是可变的,这将不是那么困难的任务;但既然是...
我正在开发一个创建事件的日历系统。我需要能够将任何事件(在一天内发生)“前滚”到用户指定的月/年。
例如,2013 年 3 月 4 日是星期一。我需要能够根据给定的月份/年份确定相应的日期 - 基于工作日及其在月份中的位置。因此,在此示例中,4 月的对应日期为 4 月 1 日,即星期一。
另一个例子:2013 年 3 月 13 日是星期三,所以 5 月的对应日期是 5 月 8 日。
如果不是因为用户提供的月/年是可变的,这将不是那么困难的任务;但既然是...
如果您有一个Dates
包含五列、FullDate
、Month
、Day
、Year
和的表DayOfWeek
,并填充了未来的日期,您可以轻松地执行以下操作。
假设@m
和@y
是用户指定的前滚月/年,@d
是事件日期:
DECLARE @weekNumInMonth int =
(
SELECT COUNT(1)
FROM Dates
WHERE Year = datepart(year @d)
AND Month = datepart(month, @d)
AND DayOfWeek = datepart(weekday, @d)
AND Day <= datepart(day, @d)
)
SELECT MAX(FullDate)
FROM
(
SELECT TOP @weekNumInMonth
FROM Dates
WHERE Year = @y
AND Month = @m
AND DayOfWeek = datepart(weekday, @d)
) x
如果没有日期表,您只需要做一些数学运算:
DECLARE @DOW int = datepart(weekday, @d)
DECLARE @firstDayInMonth date = dateadd(day, 1-datepart(day, @d), @d)
DECLARE @firstDayInMonthDOW int = datepart(weekday, @firstDayInMonth)
DECLARE @firstSameDayInMonth date =
dateadd(day, (7-(@firstDayInMonthDOW-@DOW))%7, @firstDayInMonth)
DECLARE @weekInMonth int = datediff(week, @firstSameDayInMonth, @d)
DECLARE @corr date = datefromparts(@y, @m, 1)
DECLARE @corrDOW int = datepart(weekday, @corr)
DECLARE @corrFirstSameDay date = dateadd(day, (7-(@corrDOW-@DOW))%7, @corr)
SELECT dateadd(week, @weekInMonth, @corrFirstSameDay)
这有点难看,但它的作用是:
@d
into相同@firstSameDayInMonth
。@d
以从 0 开始的整数形式确定相应月份内的第 # 周@weekInMonth
。这是 和 之间的周@firstSameDayInMonth
数@d
。@m
, year @y
with the same weekday as @d
into @corrFirstSameDay
.@weekInMonth
to @corrFirstSameDay
to get the result.Can you do it as a one-liner? Sure, just substitute your variables. Be warned though, it's ugly, and there's really nothing to be gained from it except lack of readability IMHO:
SELECT dateadd(week, datediff(week, dateadd(day, (7-(datepart(weekday, dateadd(day,
1-datepart(day, @d), @d))-datepart(weekday, @d)))%7, dateadd(day,
1-datepart(day, @d), @d)), @d), dateadd(day, (7-(datepart(weekday,
datefromparts(@y, @m, 1))-datepart(weekday, @d)))%7, datefromparts(@y, @m, 1)))