1

我正在开发一个创建事件的日历系统。我需要能够将任何事件(在一天内发生)“前滚”到用户指定的月/年。

例如,2013 年 3 月 4 日是星期一。我需要能够根据给定的月份/年份确定相应的日期 - 基于工作日及其在月份​​中的位置。因此,在此示例中,4 月的对应日期为 4 月 1 日,即星期一。

另一个例子:2013 年 3 月 13 日是星期三,所以 5 月的对应日期是 5 月 8 日。

如果不是因为用户提供的月/年是可变的,这将不是那么困难的任务;但既然是...

4

1 回答 1

1

如果您有一个Dates包含五列、FullDateMonthDayYear和的表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)

SQL 小提琴示例

这有点难看,但它的作用是:

  1. 获取该月的第一天,其工作日与@dinto相同@firstSameDayInMonth
  2. @d以从 0 开始的整数形式确定相应月份内的第 # 周@weekInMonth。这是 和 之间的周@firstSameDayInMonth@d
  3. Get the first day of month @m, year @y with the same weekday as @d into @corrFirstSameDay.
  4. Add the 0-based number of weeks @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)))
于 2013-03-01T04:03:55.920 回答