Author |
Topic |
sanjay5219
Posting Yak Master
240 Posts |
Posted - 2013-09-03 : 11:23:59
|
Hi All,I have created this script by using some help from Internet. But this articular script is not working for belowSELECT DBO.BUSINESSHOURS('2013-08-12 17:47:52.697','2013-08-13 07:48:08.207','08:30','16:30')Actually this should give 0 but it is actually returning 8 hrsCreate FUNCTION dbo.BusinessHours ( @StartDate datetime, --start of period of consideration for calculation of business hours @EndDate datetime, --end of period of consideration for calculation of business hours @BusinessStart datetime, --start of business hours @BusinessEnd datetime --end of business hours ) RETURNS int AS BEGIN DECLARE @TotalHours int IF DATEDIFF(dd,0,@StartDate)=DATEDIFF(dd,0,@EndDate) BEGIN IF @BusinessStart>@BusinessEnd BEGIN SET @TotalHours= -1 END ELSE BEGIN SELECT @BusinessStart=CASE WHEN DATEADD(dd,-DATEDIFF(dd,0,@StartDate),@StartDate) > @BusinessStart AND DATEADD(dd,-DATEDIFF(dd,0,@StartDate),@StartDate) < @BusinessEnd THEN DATEADD(dd,-DATEDIFF(dd,0,@StartDate),@StartDate) ELSE @BusinessStart END, @BusinessEnd =CASE WHEN DATEADD(dd,-DATEDIFF(dd,0,@EndDate),@EndDate) > @BusinessStart AND DATEADD(dd,-DATEDIFF(dd,0,@EndDate),@EndDate) < @BusinessEnd THEN DATEADD(dd,-DATEDIFF(dd,0,@EndDate),@EndDate) ELSE @BusinessEnd END SET @TotalHours= CASE WHEN DATEADD(dd,-DATEDIFF(dd,0,@StartDate),@StartDate) > @BusinessEnd OR DATEADD(dd,-DATEDIFF(dd,0,@EndDate),@EndDate) < @BusinessStart THEN 0 ELSE DATEDIFF(mi,@BusinessStart,@BusinessEnd)/60 END END END ELSE BEGIN SELECT @StartDate= CASE WHEN DATEADD(dd,-DATEDIFF(dd,0,@StartDate),@StartDate) > @BusinessEnd THEN DATEADD(ss,DATEDIFF(ss,0,@BusinessStart),DATEADD(dd,DATEDIFF(dd,0,@StartDate),1)) WHEN DATEADD(dd,-DATEDIFF(dd,0,@StartDate),@StartDate) < @BusinessStart THEN DATEADD(ss,DATEDIFF(ss,0,@BusinessStart),DATEADD(dd,DATEDIFF(dd,0,@StartDate),0)) ELSE @StartDate END, @EndDate= CASE WHEN DATEADD(dd,-DATEDIFF(dd,0,@EndDate),@EndDate) < @BusinessStart THEN DATEADD(ss,DATEDIFF(ss,0,@BusinessEnd),DATEADD(dd,DATEDIFF(dd,0,@EndDate),-1)) WHEN DATEADD(dd,-DATEDIFF(dd,0,@EndDate),@EndDate) > @BusinessEnd THEN DATEADD(ss,DATEDIFF(ss,0,@BusinessEnd),DATEADD(dd,DATEDIFF(dd,0,@EndDate),0)) ELSE @EndDate END ;With Calendar_CTE (Date,Day,WeekDay) AS ( SELECT DATEADD(dd,DATEDIFF(dd,0,@StartDate),0),DATENAME(dw,DATEADD(dd,DATEDIFF(dd,0,@StartDate),0)), CASE WHEN DATENAME(dw,DATEADD(dd,DATEDIFF(dd,0,@StartDate),0)) NOT IN ('Saturday','Sunday') THEN 1 ELSE 0 END UNION ALL SELECT DATEADD(dd,1,Date),DATENAME(dw,DATEADD(dd,1,Date)), CASE WHEN DATENAME(dw,DATEADD(dd,1,Date)) NOT IN ('Saturday','Sunday') THEN 1 ELSE 0 END FROM Calendar_CTE WHERE DATEADD(dd,1,Date) <= @EndDate ) SELECT @TotalHours=CEILING(SUM( CASE WHEN DATEADD(dd,DATEDIFF(dd,0,@StartDate),0)=DATEADD(dd,DATEDIFF(dd,0,@EndDate),0) THEN DATEDIFF(MINUTE,@StartDate,@EndDate) WHEN c.Date=DATEADD(dd,DATEDIFF(dd,0,@StartDate),0) THEN DATEDIFF(MINUTE,DATEADD(dd,-DATEDIFF(dd,0,@StartDate),@StartDate),@BusinessEnd) WHEN c.Date=DATEADD(dd,DATEDIFF(dd,0,@EndDate),0) THEN DATEDIFF(MINUTE,@BusinessStart,DATEADD(dd,-DATEDIFF(dd,0,@EndDate),@EndDate)) ELSE DATEDIFF(MINUTE,@BusinessStart,@BusinessEnd) END )/60) FROM Calendar_CTE c LEFT JOIN Holiday h ON h.[date]= c.Date WHERE WeekDay=1 AND h.[date] IS NULL OPTION (MAXRECURSION 0) END RETURN @TotalHours END |
|
James K
Master Smack Fu Yak Hacker
3873 Posts |
Posted - 2013-09-03 : 13:27:21
|
I can sort of see the logic you are trying to implement, but not quite enough to tell you what you might be doing wrong. It seemed too complex for what you want to accomplish - can you try the following code? It seems simpler to me (probably because it was written by yours truly, so feel free to disagree). It does return 0 for your sample data. But if you choose to use this, please test enough to satisfy yourself that it produces the correct answers. If it does not produce the correct answer, post back and I can fix it for you.DECLARE @StartDate DATETIME = '2013-08-12 17:47:52.697';DECLARE @EndDate DATETIME = '2013-08-13 07:48:08.207';DECLARE @BusinessStart TIME = '08:30'DECLARE @BusinessEnd TIME = '16:30';;WITH Calendar([Date],[IsWeekend]) AS( SELECT CAST(@StartDate AS DATE), CASE WHEN DATEDIFF(dd,0,@StartDate)%7 >= 5 THEN 1 ELSE 0 END UNION ALL SELECT DATEADD(dd,1,[Date]), CASE WHEN DATEDIFF(dd,0,DATEADD(dd,1,[Date]))%7 >= 5 THEN 1 ELSE 0 END FROM Calendar WHERE [Date] < CAST(@EndDate AS DATE)),StartTimes(StartTime, EndTime) AS( SELECT CASE WHEN CAST(@StartDate AS TIME) <= @BusinessStart THEN CAST(@BusinessStart AS TIME) WHEN CAST(@StartDate AS TIME) >= @BusinessEnd THEN CAST(@BusinessEnd AS TIME) ELSE CAST(@StartDate AS TIME) END, CASE WHEN CAST(@EndDate AS TIME) <= @BusinessStart THEN CAST(@BusinessStart AS TIME) WHEN CAST(@EndDate AS TIME) >= @BusinessEnd THEN CAST(@BusinessEnd AS TIME) ELSE CAST(@EndDate AS TIME) END)SELECT SUM( CASE WHEN c.[Date] = CAST(@StartDate AS DATE) THEN DATEDIFF(mi, StartTime, @BusinessEnd) WHEN c.[Date] = CAST(@EndDate AS DATE) THEN DATEDIFF(mi, @BusinessStart, EndTime) ELSE DATEDIFF(mi,@BusinessStart,@BusinessEnd) END)/60.0 BusinessHoursFROM Calendar c CROSS JOIN StartTimes s LEFT JOIN Holiday h ON h.Date = c.DateWHERE h.Date IS NULL AND IsWeekend = 0OPTION (MAXRECURSION 0); Edit: By the way, I assumed SQL 2008 or later. It is not too hard to modify it to make it work with earlier versions of SQL, but I noticed that you posted in SQL 2005 forum only after I posted this. |
|
|
sanjay5219
Posting Yak Master
240 Posts |
Posted - 2013-09-03 : 15:03:30
|
Thanks but if you see beloe example it is not workingIt should give 57 but it is giving 480 minDECLARE @StartDate DATETIME = '2013-08-02 02:07:11';DECLARE @EndDate DATETIME = '2013-08-02 02:57:47';DECLARE @BusinessStart TIME = '08:30'DECLARE @BusinessEnd TIME = '16:30';;WITH Calendar([Date],[IsWeekend]) AS( SELECT CAST(@StartDate AS DATE), CASE WHEN DATEDIFF(dd,0,@StartDate)%7 >= 5 THEN 1 ELSE 0 END UNION ALL SELECT DATEADD(dd,1,[Date]), CASE WHEN DATEDIFF(dd,0,DATEADD(dd,1,[Date]))%7 >= 5 THEN 1 ELSE 0 END FROM Calendar WHERE [Date] < CAST(@EndDate AS DATE)),StartTimes(StartTime, EndTime) AS( SELECT CASE WHEN CAST(@StartDate AS TIME) <= @BusinessStart THEN CAST(@BusinessStart AS TIME) WHEN CAST(@StartDate AS TIME) >= @BusinessEnd THEN CAST(@BusinessEnd AS TIME) ELSE CAST(@StartDate AS TIME) END, CASE WHEN CAST(@EndDate AS TIME) <= @BusinessStart THEN CAST(@BusinessStart AS TIME) WHEN CAST(@EndDate AS TIME) >= @BusinessEnd THEN CAST(@BusinessEnd AS TIME) ELSE CAST(@EndDate AS TIME) END)SELECT SUM( CASE WHEN c.[Date] = CAST(@StartDate AS DATE) THEN DATEDIFF(mi, StartTime, @BusinessEnd) WHEN c.[Date] = CAST(@EndDate AS DATE) THEN DATEDIFF(mi, @BusinessStart, EndTime) ELSE DATEDIFF(mi,@BusinessStart,@BusinessEnd) END) BusinessHoursFROM Calendar c CROSS JOIN StartTimes s LEFT JOIN Holiday h ON h.Date = c.DateWHERE h.Date IS NULL AND IsWeekend = 0OPTION (MAXRECURSION 0); |
|
|
sanjay5219
Posting Yak Master
240 Posts |
Posted - 2013-09-03 : 15:17:56
|
Sorry it should give 0 |
|
|
James K
Master Smack Fu Yak Hacker
3873 Posts |
Posted - 2013-09-03 : 15:17:58
|
You are right. I did not take into account the case where both start and end are on the same day. See below:DECLARE @StartDate DATETIME = '2013-08-02 02:07:11';DECLARE @EndDate DATETIME = '2013-08-02 02:57:47';DECLARE @BusinessStart TIME = '08:30'DECLARE @BusinessEnd TIME = '16:30';;WITH Calendar([Date],[IsWeekend]) AS( SELECT CAST(@StartDate AS DATE), CASE WHEN DATEDIFF(dd,0,@StartDate)%7 >= 5 THEN 1 ELSE 0 END WHERE @StartDate <= @EndDate UNION ALL SELECT DATEADD(dd,1,[Date]), CASE WHEN DATEDIFF(dd,0,DATEADD(dd,1,[Date]))%7 >= 5 THEN 1 ELSE 0 END FROM Calendar WHERE [Date] < CAST(@EndDate AS DATE)),StartTimes(StartTime, EndTime) AS( SELECT CASE WHEN CAST(@StartDate AS TIME) <= @BusinessStart THEN CAST(@BusinessStart AS TIME) WHEN CAST(@StartDate AS TIME) >= @BusinessEnd THEN CAST(@BusinessEnd AS TIME) ELSE CAST(@StartDate AS TIME) END, CASE WHEN CAST(@EndDate AS TIME) <= @BusinessStart THEN CAST(@BusinessStart AS TIME) WHEN CAST(@EndDate AS TIME) >= @BusinessEnd THEN CAST(@BusinessEnd AS TIME) ELSE CAST(@EndDate AS TIME) END)SELECT SUM( CASE WHEN c.[Date] = CAST(@StartDate AS DATE) AND c.[Date] = CAST(@EndDate AS DATE) THEN DATEDIFF(mi, StartTime, EndTime) WHEN c.[Date] = CAST(@StartDate AS DATE) THEN DATEDIFF(mi, StartTime, @BusinessEnd) WHEN c.[Date] = CAST(@EndDate AS DATE) THEN DATEDIFF(mi, @BusinessStart, EndTime) ELSE DATEDIFF(mi,@BusinessStart,@BusinessEnd) END)/60.0 BusinessHoursFROM Calendar c CROSS JOIN StartTimes s LEFT JOIN Holiday h ON h.Date = c.DateWHERE h.Date IS NULL AND IsWeekend = 0OPTION (MAXRECURSION 0); |
|
|
sanjay5219
Posting Yak Master
240 Posts |
Posted - 2013-09-03 : 15:33:24
|
Thanks Buddy you Rock |
|
|
|
|
|