SQL: How to produce next date given month and day - sql

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.

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

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

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

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

Related

Iterate by increment of parameter

I have Sql query as below example.
Select
number,age
from
tbldetails
where
month = #Month and year = #Year
union
Select
number,age
from
tblcontacts
where
month = #Month and year = #Year
Now I want to get details of above query for past 12 months of #Month and #Year and then do average on age.
Example #Month = Dec and #Year = 2015
I want to get age for Jan 2015 to Dec 2015 and then do average .
I want to use this in ssrs report.
Hoping to get some help :)
To filter for the desired date range, I would combine the year and month into one string column and then use that to compare to your converted parameters (minus one year).
WHERE CAST(YEAR AS VARCHAR(4) + RIGHT('00' + CAST(MONTH AS VARCHAR(2)), 2)
>= CAST((#YEAR - 1) AS VARCHAR(4) + RIGHT('00' + CAST(#MONTH AS VARCHAR(2)), 2)
Declare #Year int;
Set #Year = '2016'
Declare #Month varchar(10);
Set #Month = '11'
Declare #Date varchar(10);
Set #Date = Cast(#Month as varchar(2))+'-'+'01'+'-'+Cast(#year as varchar(4))
Declare #StartDate varchar(19);
Set #StartDate = Convert(varchar(19),DateAdd(m,-12,#Date),103) -- 103 dd/mm/yy
Declare #EndDate varchar(20);
Set #EndDate = Convert(varchar(20),DateAdd(m,12,#StartDate),103)
Select
Sum( StCount) as TotalStudents
(
Select Count(Rollnbr) as StCount,..
Where Date between #StartDate and #EndDate
union
Select Count(Rollnbr) as StCount,..
Where Date between #StartDate and #EndDate
)Sql1

Want to print declared date and Month

I want to get declared Month and date by the below query, but I am getting something as
Jul 21 1905 12:00AM
I want it as
Dec 31 2015
below is my query
declare #actualMonth int
declare #actualYear int
set #actualYear = 2015
set #actualMonth = 12
DECLARE #DATE DATETIME
SET #DATE = CAST(#actualYear +'-' + #actualMonth AS datetime)
print #DATE
what is wrong here
This will give you as expected output,
DECLARE #actualMonth INT
DECLARE #actualYear INT
SET #actualYear = 2015
SET #actualMonth = 12
DECLARE #DATE DATETIME;
SET #DATE = CAST(
CAST(#actualYear AS VARCHAR)+'-'+CAST(#actualMonth AS VARCHAR)+'-'+'31'
AS DATETIME
);
PRINT Convert(varchar(11),#DATE,109)
Try this,
SET #DATE = CAST(
CAST(#actualYear AS VARCHAR)+'-'+CAST(#actualMonth AS VARCHAR)+'-'+ Cast(Day(DATEADD(DAY,-1,DATEADD(month,#actualMonth,DATEADD(year,#actualYear-1900,0)))) AS VARCHAR)
AS DATETIME
);
Or this one,
SET #DATE = CAST(
CAST(#actualYear AS VARCHAR)+'-'+CAST(#actualMonth AS VARCHAR)+'-'+'01'
AS DATETIME
);
PRINT CONVERT(VARCHAR(11), DATEADD(D, -1, DATEADD(M, 1, #DATE)), 109)
You should convert those month and year to varchar and then convert the final result to datetime. It should be
DECLARE #DATE DATETIME;
SET #DATE = CAST(CAST(#actualYear AS VARCHAR) + '-' + CAST(#actualMonth AS VARCHAR) + '-' + '31' AS DATETIME);
Actually you are actualMonth and actualYear and converting as datetime it wil give other result
Try like this
declare #actualMonth int
declare #actualYear int
set #actualYear = 2015
set #actualMonth = 12
DECLARE #DATE DATETIME
SET #DATE = DATEADD(dd,-1,DATEADD(YY,1,CAST(#actualYear AS varchar(20)) ))
select SUBSTRING(convert (varchar,#DATE),0,CHARINDEX(':',convert (varchar,#DATE))-2)
print #DATE
It is no so trivial as seems. You should handle correct last days for each month.
DECLARE #actualMonth int
DECLARE #actualYear int
SET #actualYear = 2016
SET #actualMonth = 2
DECLARE #tmpDate DATETIME
SET #tmpDate = CAST(CAST(#actualYear AS VARCHAR) + RIGHT('0' + CAST(#actualMonth AS VARCHAR), 2) + '01' AS DATETIME);
SELECT CONVERT(varchar(11), DATEADD(d, -1, DATEADD(m, 1, #tmpDate)), 100)
Update
Ok, I'll try to explain problem more deeper.
What is different between extended (used by #rajeshpanchal) and basic (used by me) formats of ISO 8601?
In fact the SQL Server treats date(datetime) specified in basic and extended formats differently regarding DATEFORMAT setting.
Look at this code:
Declare #str1 varchar(8) = '20160121'
Declare #str2 varchar(10) = '2016-01-21'
Declare #dt1 datetime
Declare #dt2 datetime
--set dateformat ydm ---- 1
set dateformat ymd -----2
set #dt1 = #str1
set #dt2 = #str2
select #dt1
select #dt2
This code will work correctly. But when you uncomment first and comment second set dateformat (dateformat set to ydm) the extended format will fail when basic format will work correctly.

Conversion failed when converting date and/or time from character string calculate days

I need to calculate the totaldays in this store procedure, but I keep getting the conversion error:
DECLARE #ifIsMarch varchar(6), #addOneDay date, #startDay int,
#disconnectDay int, #startMonth int, #disconnectMonth int, #startYear
int, #disconnectYear int, #totaldays int
SELECT #startDay = DAY('2014-02-28')
SELECT #disconnectDay = DAY('2014-10-31')
SELECT #startMonth = MONTH('2014-02-28')
SELECT #disconnectMonth = MONTH('2014-10-31')
SELECT #startYear = YEAR('2014-02-28')
SELECT #disconnectYear = YEAR('2014-10-31')
print #startDay
print #disconnectDay
print #startMonth
print #disconnectMonth
print #startYear
print #disconnectYear
SELECT #addOneDay = DATEADD(DAY, 1, CONVERT(DATE, '2014-02-28'))
SELECT #ifIsMarch = LEFT(CONVERT(VARCHAR(15), #addOneDay, 110), 5)
print #addOneDay
Print #ifIsMarch
select #totaldays =
CASE
WHEN #ifIsMarch = '03-01' THEN
CASE
WHEN #DisconnectDate = '31' THEN (360*(#disconnectYear - #startYear)) + (30*(#disconnectMonth - #startMonth))
ELSE (360*(#disconnectYear - #startYear)) + (30*(#disconnectMonth - #startMonth)) + (#disconnectDay - 30)
END
END
print #totaldays
when i get conversion error with datetime, i usually change positions of month number with day number and it begins to work
to get difference between two dates i would suggest to use DATEDIFF
declare #startDate datetime = '20140228'
declare #disconnectDate datetime = '20141031'
SELECT datediff(day, #startDate, #disconnectdate)
if you have dates with -
declare #startDate datetime = convert(datetime, '2014-02-28', 21)
declare #disconnectDate datetime = convert(datetime, '2014-10-31', 21)
SELECT datediff(day, #startDate, #disconnectdate)

Date calculation in variable

I'm doing my best to set a date variable so I can compare it later. I would like something that basically says:
If the current day-of-month is less than 11, then date is 10th of LAST month
If the current day-of-month is greater-than-or-equal-to 11, then date is 10th of THIS month
Date is 11/6/2012 expected output:
#PODate = 10/10/2012
Date is 11/16/2012 expected output:
#PODate = 11/10/2012
Currently all I have is this:
DECLARE #PODate as DATETIME
Set #PODate = Convert(varchar(8),GetDate(),1)
Any tips or help would be greatly appreciated. Thank you!!
Trying to keep it as straightforward as possible:
declare #PODate datetime
select #PODate = DATEADD(month,
DATEDIFF(month,'20010110',CURRENT_TIMESTAMP) +
CASE WHEN DATEPART(day,CURRENT_TIMESTAMP) <= 10 THEN -1 ELSE 0 END,
'20010110')
The surrounding DATEADD/DATEDIFF pair are being used to normalize the date to the 10th of the current month. We then use a small CASE expression to subtract a month if the day is less than or equal to the 10th.
Whatever solution you pick, please try to avoid ones that do it as string manipulation. The usual cause of datetime related bugs in SQL is when people treat dates as strings. Keeping the data types appropriately is usually the best way to prevent these issues.
There are, admittedly, 2 strings in my solution, but these are fixed constant strings (all that matters is that they're both for the same year and month, and the second one is for the 10th of the month) and are in an unambiguous format.
Try this: SQL Fiddle
DECLARE
#PODate as DATETIME,
#LastMonth as DateTime,
#strDate as Varchar(50)
set #PODate = '11/16/2012'
set #LastMonth = DATEADD(MONTH, -1, #PODate)
if(DAY(#PODate) < 11)
SET #strDate = CAST(MONTH(#LastMonth) AS VARCHAR)+'/10/'+CAST(YEAR(#LastMonth) AS VARCHAR)
else
SET #strDate = CAST(MONTH(#PODate) AS VARCHAR)+'/10/'+CAST(YEAR(#PODate) AS VARCHAR)
Select CAST(#strDate AS DateTime)
DECLARE #PODate date = '20121116'
SELECT CASE WHEN DATEPART(day, #PODate) < 11 THEN DATEADD(mm, DATEPART(mm, GETDATE()) - DATEPART(mm, #PODate) - 1, DATEADD(day, 10 - DATEPART(day, #PODate), #PODate))
ELSE DATEADD(mm, DATEPART(mm, GETDATE()) - DATEPART(mm, #PODate), DATEADD(day, 10 - DATEPART(day, #PODate), #PODate)) END
Demo on SQLFiddle
DECLARE #currDate DATE = dbo.GetDate()
DECLARE #day INT = day(#currDate)
DECLARE #month INT
DECLARE #year INT
DECLARE #PODate DATE
IF( #day >= 11)
BEGIN
SET #month = month(#currDate)
SET #year = year(#currDate)
END
ELSE BEGIN
SET #month = month(dateadd(m,-1,#currDate))
SET #year = year(dateadd(m,-1,#currDate))
END
SET #PODate = convert(DATE,'10-' + convert(VARCHAR,#month) + '-' + convert(VARCHAR,#year))
PRINT #PODate
if #currDate = '11-jan-2013' , #PODate will be '10-jan-2013', and if #currDate = '07-jan-2013' , #PODate will be '10-Dec-2012'

SQL Server : setting two variables month and year for previous month, year roll over safe

I'm trying to basically dynamically set two variables (#month and #year) to be whatever the previous month and year were.
So in today's case #month = 7 and #year = 2012
But I want something safe for the year roll around, so if it's 1/1/2013 I would get #month = 12 and #year = 2012.
Thanks!
This is what I have.
declare #month int
declare #year int
set #month = month (getDate ())-1
set #year = 2012
You can use DATEADD to subtract a month from the current date, then grab the MONTH and YEAR portions:
DECLARE #monthAgo dateTime
DECLARE #month int
DECLARE #year int
SET #monthAgo = DATEADD(month, -1, GETDATE())
SET #month = MONTH(#monthAgo)
SET #year = YEAR(#monthAgo)
Shown in steps. You can modify the value assigned to #Now to test.
DECLARE #Now DateTime = GETDATE();
DECLARE #Then DateTime = DATEADD(Month, -1, #Now);
DECLARE #Month Int = DATEPART(Month, #Then);
DECLARE #Year Int = DATEPART(Year, #Then);
SELECT #Month, #Year;
can you not just add, after what you already have:
if #month = 0
begin
set #month = 12
set #year = #year - 1
end
As a single query, this gives the first day of last month:
select DATEADD(month,DATEDIFF(month,'20010101',CURRENT_TIMESTAMP),'20001201')
You can, if you choose, pull that apart into two separate variables, but why bother? (I assume the rest of what you're doing is working with datetimes also, rather than ints)
The two datetime strings above are selected because they have the desired relationship between them - that the second starts 1 month before the first.
Try this
declare #month int
declare #year int
Declare #dt datetime=getdate()
set #month = DATEPART(mm,DATEADD(mm,-1,#dt))
select #month
set #year = DATEPART(yy,DATEADD(mm,-1,#dt))
select #year