SQL Server : get next relative day of week. (Next Monday, Tuesday, Wed…)

后端 未结 7 1190
青春惊慌失措
青春惊慌失措 2020-12-05 07:52

What I need is a date for the next given day (Monday, Tuesday, Wed...) following today\'s date.

The user is allowed to select what day following they want and that i

相关标签:
7条回答
  • 2020-12-05 08:26

    1) Your solution uses a non-deterministic function: datepart(dw...) . Because of this aspect, changing DATEFIRST setting will gives different results. For example, you should try:

    SET DATEFIRST 7;
    your solution;
    

    and then

    SET DATEFIRST 1;
    your solution;
    

    2) Following solution is independent of DATEFIRST/LANGUAGE settings:

    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
    

    Result:

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

    This solution is based on following property of DATETIME type:

    • Day 0 = 19000101 = Mon

    • Day 1 = 19000102 = Tue

    • Day 2 = 19000103 = Wed

    ...

    • Day 5 = 19000106 = Sat

    • Day 6 = 19000107 = Sun

    So, converting INT value 0 to DATETIME gives 19000101.

    If you want to find the next Wednesday then you should start from day 2 (19000103/Wed), compute days between day 2 and current day (20130921; 41534 days), divide by 7 (in order to get number of full weeks; 5933 weeks), multiple by 7 (41531 fays; in order to get the number of days - full weeks between the first Wednesday/19000103 and the last Wednesday) and then add 7 days (one week; 41538 days; in order to get following Wednesday). Add this number (41538 days) to the starting date: 19000103.

    Note: my current date is 20130921.

    Edit #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
    

    Result:

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

    Note: my current date is 20130923.

    0 讨论(0)
  • 2020-12-05 08:30

    I made this as a function, in which the procedure uses available streamlined knowledge thus it's, I think, a robust solution.

    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
    
    0 讨论(0)
  • 2020-12-05 08:34

    I think this is the best way of doing of finding the next Monday

    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,
    
    0 讨论(0)
  • 2020-12-05 08:35

    It's an old question. But I'm sure that posting better solution worth it.

    -- 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)
    

    This solution is improved solution of @Bogdan Sahlean. It can operate @NextDayID that is greater than 6. So you can, for example, find 2nd Monday from today.

    Following query shows that my solution works correctly.

    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
    

    Result:

    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
    

    This solution doesn't depend on @@datefirst.

    0 讨论(0)
  • 2020-12-05 08:40

    The following function enables to you generate the table on-the-fly...this is how I usually do it...I don't like the idea of a perm date table...seems unnecessary, but every person and situation are different :-)

    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
    
    0 讨论(0)
  • 2020-12-05 08:48

    Try this: This will give the date for required weekday in a month.

     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
    
    0 讨论(0)
提交回复
热议问题