April 7, 2006 at 4:59 pm
Does anybody know if a UDF that will return the full date given a week of year and the year?
I am speaking of the datepart() week. So given year 2006 and week 14. How can I get the full date? e.g. April 2, 2006
Or get full date from dayofyear.
I can get day of year using this formula but it doesnt get me that much closer.
(wk#*7)-(dow of week of Jan 1)
So the 14th week would be (14*7)-1 = 97
Is there a native function or a udf for converting week or day of year into a date?
Thanks,
Dave
Trainmark.com IT Training B2B Marketplace
(Jobs for IT Instructors)
April 7, 2006 at 5:10 pm
Doh! Nevermind, if I have dayOfYear its a simply dateadd() from Jan 1 to get the date I am after.
Well sometime it helps to write down my question so that I can figure it out
Dave
Trainmark.com IT Training B2B Marketplace
(Jobs for IT Instructors)
April 7, 2006 at 5:33 pm
OK to answer my own question more fully, here are two UDF's I created to return the start and end of a week given a week number and a year. They are designed for bounding all times in a given week so the weekEnd returns as "[date] 23:59:59".
I am sure greater minds could write better functions but these will do for me.
CREATE FUNCTION [dbo].[udf_weekstart]
(
@wk int,
@year int
)
RETURNS datetime AS
BEGIN
declare @DW int
declare @dy int
declare @weekstart datetime
set @DW = datepart(dw,'Jan 1, ' + cast(@year as varchar(4)))
select @dy = (@wk*7)
set @weekstart = dateadd(wk,-1,dateadd(d,@dy,'Jan 1, ' + cast(@year as varchar(4))))
cast(@year as varchar(4))))
return @weekstart
END
CREATE FUNCTION [dbo].[udf_weekend]
(
@wk int,
@year int
)
RETURNS datetime AS
BEGIN
declare @DW int
declare @dy int
declare @weekEnd datetime
set @DW = datepart(dw,'Jan 1, ' + cast(@year as varchar(4)))
select @dy = (@wk*7)
set @weekend = dateadd(d,-1,dateadd(d,@dy,'Jan 1, ' + cast(@year as varchar(4))))
set @weekend = dateadd(s,-1,dateadd(d,1,@weekend))
return @weekend
END
Dave
Trainmark.com IT Training B2B Marketplace
(Jobs for IT Instructors)
April 7, 2006 at 8:38 pm
Very nice... very nice indeed...
These might execute a bit quicker... in fact, considering that they're single line formulas, you may not want to use them as functions, at all.. just use the formulas...
CREATE FUNCTION dbo.udf_WeekStart (@Year INT, @Week INT) RETURNS DATETIME AS BEGIN RETURN DATEADD(wk,@Week,DATEADD(yy,@Year-1900,0)) END
CREATE FUNCTION dbo.udf_WeekEnd (@Year INT, @Week INT) RETURNS DATETIME AS BEGIN RETURN DATEADD(ms,-3,DATEADD(wk,@Week+1,DATEADD(yy,@Year-1900,0))) END
Hope these help...
--Jeff Moden
Change is inevitable... Change for the better is not.
April 7, 2006 at 8:46 pm
Thanks Jeff, I'll probably replace mine with yours, thanks for that.
Tell me, is there a performance hit for wrapping a formula like this in a function? In some large queries it helps sometimes to call it as a function rather then an inline formula, but if there is a significant performance hit I may stop that practice.
Cheers
Dave
Dave
Trainmark.com IT Training B2B Marketplace
(Jobs for IT Instructors)
April 8, 2006 at 9:31 am
Dave,
Very volitile subject... I got involved with a pretty big discussion on this subject before and I'll just say that, in all the "million-row" testing I did, I satisfied myself that properly constucted UDF's are usually just as fast (sometimes, even faster) as equivalent in-line code and that the benefits of using them (self-documenting because of their name if properly named, faster development because you don't have to look-up complicated formulas, consistency because they always do the same thing, simplified testing because they've already been tested if you do it right, readability of the code, etc, etc) make them worth using even if there is a minor performance hit on some of them.
To summarize, I very successfully use UDF's for this type of thing all the time and the only reason I mentioned using the formulas directly was to offer a second option if you needed it.
As a side-bar, one caveat you may wish to avoid is calling one function within another... I haven't tested the performance of nested UDF's but they're a real pain in the patootie to troubleshoot if something goes wrong just as deeply nested single record stored procs can be.
--Jeff Moden
Change is inevitable... Change for the better is not.
April 8, 2006 at 9:46 am
Great, thanks for that, I think I will continue using UDF's for code readability and consistancy. In the current app I am working on I need to copnvert varchar dates to datetimes, convert to and from UTC allot, and expand to proper full day bounding. The functions sure make the code read better
I found that nesting UDF did sometimes make things harder to debug so I already try not to do that.
Dave
Trainmark.com IT Training B2B Marketplace
(Jobs for IT Instructors)
April 8, 2006 at 11:17 am
You shouldn't necessarily need a function to convert a VARCHAR date to a datetime to save in a table... it's one of those "instrinsic conversions" that happen auto-magically if the format is something that SQL recognizes. The exception to that rule is if the varchar date is in the format of dd/mm/yyyy instead of mm/dd/yyyy.
If the proper full day bounding you are talking about is similar to the week bounding in your previous post, consider this instead of using 23:59:59.997 as part of the end-bound (misses 3 milliseconds of the day, requires a bit of extra coding in the UDF making it a bit slower, etc)...
In a literal format, let's say that you want to find all records from yesterday that have a datetime column... you could do this (in your previous post, it would require 2 functions)...
SELECT * FROM yourtable WHERE somedatecol BETWEEN DATEADD(dd,DATEDIFF(dd,0,GETDATE()-1),0) AND DATEADD(dd,DATEDIFF(dd,0,GETDATE()-1),0)+'23:59:59.997'
In your previous post, each formula would be represented by a function, one taking longer than the other because of the handling of the time component.
If you do it like the following, you would only need 1 function, there would be no time component, and you wouldn't miss the 3 milliseconds (min resolution of datetime)...
SELECT * FROM yourtable WHERE somedatecol >= DATEADD(dd,DATEDIFF(dd,0,GETDATE()-1),0) --Yesterday at midnight AND somedatecol < DATEADD(dd,DATEDIFF(dd,0,GETDATE() ),0) --Today at midnight
There's not much extra coding (column name listed twice), one less function is required, it'll run faster because we don't need to add the 23:59:59.997 time, and there's no chance of missing something that may come in as a varchar time in the missing 3 milliseconds.
If the function looked like this...
CREATE FUNCTION dbo.fWholeDate(@MyDate DATETIME)
RETURNS DATETIME
AS
-- This function removes the time element from a datetime (sets it to midnight)
BEGIN
RETURN DATEADD(dd,DATEDIFF(dd,0,@MyDate),0)
END
...Then the SQL would look like this...
SELECT * FROM yourtable WHERE somedatecol >= dbo.fWholeDate(GETDATE()-1) --Yesterday at midnight AND somedatecol < dbo.fWholeDate(GETDATE() ) --Today at midnight
A hidden benefit is that the function will automatically convert VARCHAR dates provided that they are in the format SQL recognizes as stated before.
--Jeff Moden
Change is inevitable... Change for the better is not.
April 8, 2006 at 6:53 pm
Just a follow up... I did some million row testing on the simple functions we created here...
On a quiet multiprocessor box, the functions returned about 12% faster than the inline code but was more expensive on CPU time used and disk I/O. Duration for the million row test on the function was about 8 seconds.
On a quiet single processor box, the inline code returned neary twice as fast as the function and was still less expensive on CPU time used and disk I/O. Duration for the million row test on the inline code was about 10 seconds.
The bottom line, especially on such simple functions, is that you have to do some load testing so you can make an intelligent decision as to whether or not to use the function. That decision making process includes those other hidden benefits of self documentation, consistancy, and readable code.
--Jeff Moden
Change is inevitable... Change for the better is not.
Viewing 9 posts - 1 through 8 (of 8 total)
You must be logged in to reply to this topic. Login to reply