UFN_RECURRENCE_CALCULATEACTUALSTARTDATE

Determines the effective start date for a recurrence. This is the first actual occurrence after the supplied start date.

Return

Return Type
date

Parameters

Parameter Parameter Type Mode Description
@RECURRENCETYPE tinyint IN
@DAYOFWEEK tinyint IN
@DAY tinyint IN
@WEEK tinyint IN
@MONTH tinyint IN
@STARTDATE date IN

Definition

Copy


            CREATE function [DBO].[UFN_RECURRENCE_CALCULATEACTUALSTARTDATE]
            (
                @RECURRENCETYPE tinyint = 0,
                @DAYOFWEEK tinyint = 0,
                @DAY tinyint = 0,
                @WEEK tinyint = 0,
                @MONTH tinyint = 0,
                @STARTDATE date = null
            )
            returns date
            begin

                --Have to convert DATE type to DATETIME for the following math to be allowed

                declare @RESULT datetime = @STARTDATE;
                declare @TEMPDAYOFWEEK int;
                declare @TEMPDAYOFWEEKBIT int;
                declare @BEGINNINGOFMONTH datetime;
                declare @DAYSINMONTH int;

                if @RECURRENCETYPE = 1 set @DAYOFWEEK=62; --Mon thru Fri




                --Fix Day of Week. This is duplicated in "Special Case for 6"

                if @RECURRENCETYPE IN (1,2,4,6)
                begin
                    if @DAYOFWEEK NOT BETWEEN 1 AND 127 return @RESULT;

                    set @TEMPDAYOFWEEK = (datepart(DW, @RESULT) + @@datefirst - 1) % 7 + 1
                    set @TEMPDAYOFWEEKBIT = power(2, @TEMPDAYOFWEEK-1)

                    while (@DAYOFWEEK & @TEMPDAYOFWEEKBIT) = 0
                    begin
                        set @RESULT = dateadd(DD, 1, @RESULT);
                        set @TEMPDAYOFWEEK = (datepart(DW, @RESULT) + @@datefirst - 1) % 7 + 1
                        set @TEMPDAYOFWEEKBIT = power(2, @TEMPDAYOFWEEK-1)
                    end
                end


                --Fix Day of Month

                if @RECURRENCETYPE IN (3,5)
                begin
                    if @DAY NOT BETWEEN 1 AND 31 return @RESULT
                    while day(@RESULT) != @DAY
                        set @RESULT = dateadd(DD, 1, @RESULT);
                end


                --Fix Week-Of-Month. This is duplicated in "Special Case for 6"

                if @RECURRENCETYPE IN (4,6)
                begin
                    if @WEEK NOT BETWEEN 1 AND 5 return @RESULT;
                    if @WEEK = 5
                    begin
                        --Handle the "last week" case

                        set @BEGINNINGOFMONTH = @RESULT - day(@RESULT) + 1
                        set @DAYSINMONTH = datediff(DD, @BEGINNINGOFMONTH, dateadd(MM, 1, @BEGINNINGOFMONTH))

                        while (@DAYSINMONTH - day(@RESULT)) >= 7
                        begin
                            set @RESULT = dateadd(WK, 1, @RESULT);
                            set @BEGINNINGOFMONTH = @RESULT - day(@RESULT) + 1
                            set @DAYSINMONTH = datediff(DD, @BEGINNINGOFMONTH, dateadd(MM, 1, @BEGINNINGOFMONTH))
                        end            

                    end
                    else
                    begin
                        while ((day(@RESULT) - 1) / 7) + 1 != @WEEK
                            set @RESULT = dateadd(WK, 1, @RESULT);
                    end        
                end    


                --Special handling for RecurType 6:

                declare @MONTHWASADJUSTED bit = 0;


                --Fix Month of Year

                if @RECURRENCETYPE IN (5,6)
                begin
                    declare @TEMPMONTH int = datepart(MM, @RESULT);
                    declare @COUNTER int = 0;

                    if @TEMPMONTH != @MONTH
                        set @MONTHWASADJUSTED = 1;

                    --Using a counter rather than updateing @RESULT each time b/c if Day is 31 and we

                    --go through a month with 30 days, our day will drop down to that on the Add Month command.

                    while @TEMPMONTH != @MONTH
                    begin
                        set @COUNTER = @COUNTER + 1;
                        set @TEMPMONTH = datepart(MM, dateadd(MM, @COUNTER, @RESULT));
                    end

                    set @RESULT = dateadd(MM, @COUNTER, @RESULT);
                end

                if @RECURRENCETYPE = 5 AND @MONTH = 2 AND @DAY = 29 AND datepart(DD, @RESULT) = 28 
                begin
                    while datepart(DD, dateadd(DD, 1, @RESULT)) != 29
                        set @RESULT = dateadd(YY, 1, @RESULT);
                    set @RESULT = dateadd(DD, 1, @RESULT);
                end    

                -- Special Case for 6

                if @RECURRENCETYPE = 6 AND @MONTHWASADJUSTED = 1
                begin
                    --- Because we had to adjust the month, then we are no longer on

                    --- the "Nth" "Day" of the month.  We need to readjust those vales.

                    --- We also back back up to the first day of the month without fear 

                    --- of going to before the provided start date, b/c the month was advanced.


                    --Go back to day one, and advance from there.

                    set @RESULT = @RESULT - day(@RESULT) + 1

                    --Fix Day of Week again.

                    set @TEMPDAYOFWEEK = (datepart(DW, @RESULT) + @@datefirst - 1) % 7 + 1
                    set @TEMPDAYOFWEEKBIT = power(2, @TEMPDAYOFWEEK-1)        
                    while (@DAYOFWEEK & @TEMPDAYOFWEEKBIT) = 0
                    begin
                        set @RESULT = dateadd(DD, 1, @RESULT);
                        set @TEMPDAYOFWEEK = (datepart(DW, @RESULT) + @@datefirst - 1) % 7 + 1
                        set @TEMPDAYOFWEEKBIT = power(2, @TEMPDAYOFWEEK-1)
                    end

                    --Fix Week of Month again.

                    if @WEEK = 5
                    begin
                        --Handle the "last week" case

                        set @BEGINNINGOFMONTH = @RESULT - day(@RESULT) + 1
                        set @DAYSINMONTH = datediff(DD, @BEGINNINGOFMONTH, dateadd(MM, 1, @BEGINNINGOFMONTH))

                        while (@DAYSINMONTH - day(@RESULT)) >= 7
                        begin
                            set @RESULT = dateadd(WK, 1, @RESULT);
                            set @BEGINNINGOFMONTH = @RESULT - day(@RESULT) + 1
                            set @DAYSINMONTH = datediff(DD, @BEGINNINGOFMONTH, dateadd(MM, 1, @BEGINNINGOFMONTH))
                        end            

                    end
                    else
                    begin
                        while ((day(@RESULT) - 1) / 7) + 1 != @WEEK
                            set @RESULT = dateadd(WK, 1, @RESULT);
                    end

                end

                return @RESULT

            end