16

我需要的是今天日期之后的下一个特定日期(星期一、星期二、星期三...)的日期。

允许用户选择他们想要的第二天,并将其作为 int 存储在表格中。“下周二给我打电话(3)”

Sunday = 1
Monday = 2
Tuesday = 3
...

所以我的桌子看起来像这样。

UserID, NextDayID

我想出的是:

select dateadd(dd,(7 - datepart(dw,GETDATE()) + NextDayID ) % 7, getdate())

它似乎有效,并且如果您要求下一个今天的任何一天,它将返回今天的日期,如果需要,我可以添加一周。

我想知道的是,这是一个好的解决方案还是我缺少什么?

4

8 回答 8

39

1)您的解决方案使用非确定性函数:datepart(dw...). 由于这个方面,改变DATEFIRST设置会产生不同的结果。例如,您应该尝试:

SET DATEFIRST 7;
your solution;

接着

SET DATEFIRST 1;
your solution;

2)以下解决方案独立于DATEFIRST/LANGUAGE设置:

DECLARE @NextDayID INT  = 0 -- 0=Mon, 1=Tue, 2 = Wed, ..., 5=Sat, 6=Sun
SELECT DATEADD(DAY, (DATEDIFF(DAY, @NextDayID, GETDATE()) / 7) * 7 + 7, @NextDayID) AS NextDay

结果:

NextDay
-----------------------
2013-09-23 00:00:00.000

该解决方案基于以下DATETIME类型的属性:

  • 第 0 天 = 19000101= 星期一

  • 第 1 天 = 19000102= 周二

  • 第 2 天 = 19000103= 星期三

...

  • 第 5 天 = 19000106= 周六

  • 第 6 天 = 19000107= 太阳

因此,将 INT 值 0 转换为 DATETIME 给出19000101.

如果你想找到下一个,Wednesday那么你应该从第 2 天(19000103/ Wed)开始,计算第 2 天和当天之间的天数(20130921; 41534 天),除以 7(以获得完整周数; 5933 周),倍数乘以 7(41531 天;为了得到天数 - 第一个 Wednesday/19000103和最后一个之间的整周Wednesday),然后加上 7 天(一周;41538 天;为了得到关注Wednesday)。将此数字(41538 天)添加到开始日期:19000103

注意:我当前的日期是20130921.

编辑#1:

DECLARE @NextDayID INT;
SET @NextDayID = 1; -- Next Sunday
SELECT DATEADD(DAY, (DATEDIFF(DAY, ((@NextDayID + 5) % 7), GETDATE()) / 7) * 7 + 7, ((@NextDayID + 5) % 7)) AS NextDay

结果:

NextDay
-----------------------
2013-09-29 00:00:00.000 

注意:我当前的日期是20130923.

于 2013-09-20T21:26:14.600 回答
1

日历表是使用一堆日期函数和日期算术的替代方法。这个特定问题的最小日历表可能看起来像这样。

2013-09-20  Fri
2012-09-21  Sat
2012-09-22  Sun
2012-09-23  Mon
2012-09-24  Tue
...

因此,获取下周一的查询可能如下所示。

select min(cal_date)
from calendar
where cal_date > current_date
  and day_of_week = 'Mon';

在实践中,您可能希望日历表中有更多列,因为您会发现它有很多用途。

此外,通常可以看出使用日历表的代码显然是正确的。阅读上面的代码很简单:选择今天之后且在星期一的最小日历日期。很少看到依赖日期函数和日期算术的代码显然是正确的。

PostgreSQL 中的日历表

于 2013-09-20T15:38:03.457 回答
1

这是一个老问题。但我确信发布更好的解决方案值得。

-- 0 = 1st Mon, 1 = 1st Tue, 2 = 1st Wed, ..., 5 = 1st Sat, 6 = 1st Sun
-- 7 = 2nd Mon, 8 = 2nd Tue, ...
declare @NextDayID int = 0, @Date date = getdate()

select cast (cast (
    -- last Monday before [Date] inclusive, starting from 1900-01-01
    datediff (day, @NextDayID % 7, @Date) / 7 * 7
    -- shift on required number of days
    + @NextDayID + 7
    as datetime) as date)

该解决方案是@Bogdan Sahlean 的改进解决方案。它可以操作大于 6 的@NextDayID。例如,您可以找到从今天开始的第 2 个星期一。

以下查询显示我的解决方案工作正常。

select [Date]
    , convert (char(5), [0], 10) as Mon1
    , convert (char(5), [1], 10) as Tue1
    , convert (char(5), [2], 10) as Wed1
    , convert (char(5), [3], 10) as Thu1
    , convert (char(5), [4], 10) as Fri1
    , convert (char(5), [5], 10) as Sat1
    , convert (char(5), [6], 10) as Sun1
    , convert (char(5), [7], 10) as Mon2
    , convert (char(5), [8], 10) as Tue2
from (
    select [Date], NextDayID
        , cast (cast (
          datediff (day, NextDayID % 7, [Date]) / 7 * 7 -- last Monday before [Date] inclusive, starting from 1900-01-01
        + NextDayID + 7 -- shift on required number of days
        as datetime) as date) as NextDay
    from (
        select datefromparts (2018, 5, dt) as [Date]
        from (values(14),(15),(16),(17),(18),(19),(20))t_(dt)
    ) d
    cross join (values(0),(1),(2),(3),(4),(5),(6),(7),(8))nd(NextDayID)
) t
pivot (
    min (NextDay) for NextDayID in ([0], [1], [2], [3], [4], [5], [6], [7], [8])
) pvt

结果:

Date       | Mon1  | Tue1  | Wed1  | Thu1  | Fri1  | Sat1  | Sun1  | Mon2  | Tue2
-----------+-------+-------+-------+-------+-------+-------+-------+-------+------
2018-05-14 | 05-21 | 05-15 | 05-16 | 05-17 | 05-18 | 05-19 | 05-20 | 05-28 | 05-22
2018-05-15 | 05-21 | 05-22 | 05-16 | 05-17 | 05-18 | 05-19 | 05-20 | 05-28 | 05-29
2018-05-16 | 05-21 | 05-22 | 05-23 | 05-17 | 05-18 | 05-19 | 05-20 | 05-28 | 05-29
2018-05-17 | 05-21 | 05-22 | 05-23 | 05-24 | 05-18 | 05-19 | 05-20 | 05-28 | 05-29
2018-05-18 | 05-21 | 05-22 | 05-23 | 05-24 | 05-25 | 05-19 | 05-20 | 05-28 | 05-29
2018-05-19 | 05-21 | 05-22 | 05-23 | 05-24 | 05-25 | 05-26 | 05-20 | 05-28 | 05-29
2018-05-20 | 05-21 | 05-22 | 05-23 | 05-24 | 05-25 | 05-26 | 05-27 | 05-28 | 05-29

此解决方案不依赖于@@datefirst.

于 2018-05-14T23:03:35.793 回答
1

我认为这是找到下周一的最佳方法

CONVERT(VARCHAR(11),DateAdd(DAY,case 
     when (DateName(WEEKDAY, NextVisitDate) ='Tuesday') Then 6 
     when (DateName(WEEKDAY, NextVisitDate) ='Wednesday') Then 5 
     when (DateName(WEEKDAY, NextVisitDate) ='Thursday') Then 4
     when (DateName(WEEKDAY, NextVisitDate) ='Friday') Then 3 
     when (DateName(WEEKDAY, NextVisitDate) ='Saturday') Then 2
     when (DateName(WEEKDAY, NextVisitDate) ='Sunday') Then 1
     else 0 end, DateAdd(DAY, DateDiff(DAY, 0,  NextVisitDate), 0)),106) AS Monday,
于 2019-07-29T12:24:41.723 回答
1

如果今天是需要找出的那一天,则查找下一个即将到来的日子,包括今天。

只需稍作调整... 将变量 @weekdayno 设置如下:1 = 星期日,2 = 星期一,3 = 星期二,4 = 星期三,5 = 星期四,6 = 星期五,7 = 星期六

    DECLARE @weekdayno INT 
    DECLARE @todayno INT 

    SET @weekdayno = 2  ---For Monday----
    SET @todayno = DATEPART(dw,GETDATE()) 

    SELECT CASE 
    WHEN (@todayno = @weekdayno) 
        THEN CONVERT(varchar, GETDATE(), 101) 

    WHEN (@todayno < @weekdayno) 
        THEN CONVERT(varchar, (@weekdayno - @todayno + GETDATE()), 101) 

    WHEN (@todayno > @weekdayno) 
        then CONVERT(varchar,(GETDATE() - (@todayno - @weekdayno) + 7), 101) 

    END AS UpcomingOrToday
于 2021-06-17T13:13:43.853 回答
0

以下功能使您可以即时生成表格...这是我通常这样做的方式...我不喜欢烫发日期表的想法...似乎没有必要,但是每个人和情况是不同的 :-)

CREATE function [dbo].[fxDateTable]
(
    @begindate datetime = null
,   @enddate datetime = null
)
RETURNS @dates TABLE
(
            EventDate datetime primary key not null
)
as
begin
    select @enddate = isnull(@enddate, getdate())
    select @begindate = isnull(@begindate, dateadd(day, -3, @enddate))

    insert @dates
    select dateadd(day, number, @begindate)
    from 
        (select distinct number from master.dbo.spt_values
         where name is null
        ) n
    where dateadd(day, number, @begindate) < @enddate

    return
end
于 2015-04-09T21:18:30.037 回答
0

我把它作为一个函数,其中过程使用可用的简化知识,因此我认为它是一个强大的解决方案。

CREATE FUNCTION [nilnul.time_._dated.date].[NextWeekday]
(
    @nextWeekDay int  -- sunday as firstday is 1.
)
RETURNS datetime
AS
BEGIN


declare @time datetime;
set @time=getdate();

declare @weekday int;
set @weekday = datepart(weekday,  @time) ;

declare @diff int;
set @diff= @nextWeekDay-@weekday;

--modulo 7 bijectively
declare @moduloed int;
set @moduloed = case 
    when @diff <=0 then @diff+7 
    else @diff
end;

return dateadd(day, @moduloed,  @time);

END
于 2020-09-12T12:13:45.770 回答
0

试试这个:这将给出一个月中所需工作日的日期。

 declare @monthstartdate date='2020-01-01',@monthenddate date='2020-01-31',@weekday char(9)='thursday',@weeknum int=4

        ; with cte(N,WeekDayName_C,Date_C) as
        (select 1,datename(WEEKDAY,@monthstartdate),@monthstartdate
        union all
        select n+1,datename(WEEKDAY,dateadd(day,n,@monthstartdate)),dateadd(day,n,@monthstartdate) from cte where n<31 and Date_C<=@monthenddate )
        select * from (select *,ROW_NUMBER() over (partition by WeekDayName_C order by Date_C asc)Weeknum from cte)a
        where WeekDayName_C=@weekday and Weeknum=@weeknum
于 2020-01-21T05:55:56.783 回答