In my table I have a Month(tinyint) and a Day(tinyint) field. I would like to have a function that takes this month and day and produces a datetime for the next date(including year) given this month and day.
So if I had Month = 9, Day = 7 it would produce 9/7/2009.
If I had Month 1, Day 1 it would produce 1/1/2010.
views:
648answers:
4
+1
A:
Here is my sql example so far. I don't really like it though...
DECLARE @month tinyint,
@day tinyint,
@date datetime
SET @month = 1
SET @day = 1
-- SET DATE TO DATE WITH CURRENT YEAR
SET @date = CONVERT(datetime, CONVERT(varchar,@month) + '/' + CONVERT(varchar,@day) + '/' + CONVERT(varchar,YEAR(GETDATE())))
-- IF DATE IS BEFORE TODAY, ADD ANOTHER YEAR
IF (DATEDIFF(DAY, GETDATE(), @date) < 0)
BEGIN
SET @date = DATEADD(YEAR, 1, @date)
END
SELECT @date
Justin Balvanz
2009-06-23 20:24:21
Don't use MM/DD/YYYY format for date literals. Use YYYYMMDD instead. It will avoid localization issues, and it sorts properly.
Peter
2009-06-23 20:35:45
Otherwise, I don't see a problem with your method. Do you dislike the conversion from a literal?
Peter
2009-06-23 20:45:49
It seems like something that there should be some easy solution to.
Justin Balvanz
2009-06-23 20:48:54
Can you give me an example on how to format it this way? I'm having troubles turning Month=1 into a string of "01".
Justin Balvanz
2009-06-23 20:54:16
I added another method that doesn't require date literals at all.
Peter
2009-06-23 21:06:16
Great! Thanks Peter!
Justin Balvanz
2009-06-23 21:16:39
+1
A:
Here's a solution with PostgreSQL
your_date_calculated = Year * 10000 + Month * 100 + Day
gives you a date like 20090623.
select cast( cast( your_date_calculated as varchar ) as date ) + 1
Luc M
2009-06-23 20:28:21
+2
A:
something like this would work. It's variation on your method, but it doesn't use the MM/DD/YYYY literal format, and it won't blowup against bad input (for better or for worse).
declare @month tinyint
declare @day tinyint
set @month = 9
set @day = 1
declare @date datetime
-- this could be inlined if desired
set @date = convert(char(4),year(getdate()))+'0101'
set @date = dateadd(month,@month-1,@date)
set @date = dateadd(day,@day-1,@date)
if @date <= getdate()-1
set @date = dateadd(year,1,@date)
select @date
Alternatively, to create a string in YYYYMMDD format:
set @date =
right('0000'+convert(char(4),year(getdate())),4)
+ right('00'+convert(char(2),@month),2)
+ right('00'+convert(char(2),@day),2)
Another method, which avoids literals all together:
declare @month tinyint
declare @day tinyint
set @month = 6
set @day = 24
declare @date datetime
declare @today datetime
-- get todays date, stripping out the hours and minutes
-- and save the value for later
set @date = floor(convert(float,getdate()))
set @today = @date
-- add the appropriate number of months and days
set @date = dateadd(month,@month-month(@date),@date)
set @date = dateadd(day,@day-day(@date),@date)
-- increment year by 1 if necessary
if @date < @today set @date = dateadd(year,1,@date)
select @date
Peter
2009-06-23 20:34:17
+1
A:
Here's my version. The core of it is just two lines, using the DATEADD
function, and it doesn't require any conversion to/from strings, floats or anything else:
DECLARE @Month TINYINT
DECLARE @Day TINYINT
SET @Month = 9
SET @Day = 7
DECLARE @Result DATETIME
SET @Result =
DATEADD(month, ((YEAR(GETDATE()) - 1900) * 12) + @Month - 1, @Day - 1)
IF (@Result < GETDATE())
SET @Result = DATEADD(year, 1, @Result)
SELECT @Result
LukeH
2009-06-23 22:12:19
Nice. How about an in-line version to avoid the function call overhead? eg, SELECT DATEADD(year,<expression here>,DATEADD(month, ((YEAR(GETDATE()) - 1900) * 12) + MonthField - 1, DayField - 1)) as NewDate FROM ....
Peter
2009-06-24 02:10:26