TSQL Next Payment Date February - sql-server

My function works throughout the year, to respond with the next payment date of the month for a scheduled transaction. When spanning over to next year however, it fails with "Conversion failed when converting date and/or time from character string."
The first date is the start of a chosen month. The second date is the due date of a transaction, an entry from a list of many transactions with dates. It works all year until I get past the end of the year.
How would I fix this to respond with the correct date?
SELECT dbo.NextPaymentDate('2/1/2017', '1/30/2017')
returns 2/28/2017
SELECT dbo.NextPaymentDate('2/1/2017', '12/30/2016')
returns
Conversion failed when converting date and/or time from character string
Code:
--SELECT dbo.NextPaymentDate('2/1/2017','12/30/2016')
ALTER FUNCTION [dbo].[NextPaymentDate]
(#RegisterDate DATE, #PaymentDueDate DATE)
RETURNS DATE
AS
BEGIN
DECLARE #returnDate DATE, #MonthDiff int
SET #MonthDiff = MONTH(#RegisterDate) - MONTH(#PaymentDueDate)
SELECT #returnDate =
CAST(CONVERT(varchar, YEAR(#RegisterDate)) + '-'
+ CONVERT(varchar, MONTH(#RegisterDate)) + '-'
+ CONVERT(varchar, DAY(DATEADD(mm, #MonthDiff, #PaymentDueDate))) AS DATE)
RETURN #returnDate
END

Seems the issue was with the #MonthDiff, it was returning a negative value and the casting was creating a double negative, literally, --, with the datepart separators
I changed to this, and ran a few tests and seems to work for many date variations
SET #MonthDiff = ABS(DATEDIFF(MONTH, #RegisterDate, #PaymentDueDate))

Related

Convert a date format as text - day month

Insert a column: received_by as text in the format of Day Month.
i.e. 25/06/2018 should be inserted as 25 June. The format dd/mm/yyyy should be converted into day month - whereby month should be written out.
You can use below select statement to get the desired return
select FORMAT(convert(datetime, '25/06/2018', 103), 'dd MMMM')
Or You can create the custom function in SQL server which will take a date in 'dd/mm/yyyy' format and return day and month as required. use below code to achieve the desired result.
create function GetDateDaynMonth(#date varchar(20))
returns varchar(20)
as
begin
declare #DaynMonth varchar (20)
SELECT #DaynMonth = FORMAT (convert(datetime, #date, 103), 'dd MMMM')
return #DaynMonth;
end
go
select dbo.GetDateDaynMonth('25/06/2018')

Write a single query to search between two dates and when To date is not available then it should search greater then first date

Write a single query to search between two dates and when To date is not available then it should search greater then first date.
For example: search between two dates, when both from and to dates are available
11-10-2015 to 11-10-2017
My query should also return result when To date is not available
For example: I want to write single query without any if and else
This code works and it is a single statement, as requested.
SELECT * from MyTable WHERE recordingdate BETWEEN COALESCE(#startdate,CAST('01/01/1753 00:00:00.000' AS DATETIME)) AND COALESCE(#enddate,CAST('12/31/9999 23:59:59.997' AS DATETIME))
If the start date is NULL, COALESCE will return the minimum date value, as defined by SQL Server. Otherwise, it returns the start date value sent in.
If the end date is NULL, COALESCE will return the maximum date value, as defined by SQL Server. Otherwise, it returns the end date sent in.
Feel free to turn the COALESCE statements for MIN and MAX possible dates into functions, as SQL Server does not have built-in functions for minimum and maximum possible dates.
Writing your code this way allows you to always execute a BETWEEN.
Try Thie below Logic
DECLARE #FromDt DATE='01/01/2017',#ToDate DATE = NULL
SELECT
*
FROM YourTable
WHERE FromDate > #FromDate
AND
(
#ToDate IS NULL
OR
(
#ToDate IS NOT NULL
AND
ToDate > #ToDate
)
)
declare #dt_from date = '20151011',
#dt_to date = '20171011' -- null
select *
from dbo.your_table
where date_field >= #dt_from and data <= isnull(#dt_to, '99990101');

How to convert int year into valid date format in my stored procedure

My stored proc has the following select statement:
select Name,Holiday from tblNames where ID = #ID and DATENAME(YEAR, GETDATE()) = #Year
When executing the statement I have an error
"Error converting data type int to nvarchar."
How can I convert #Year parameter to a correct year?
The return type of the datename function is nvarchar, you want the datepart function that returns an integer value, so change to DATEPART(YEAR, GETDATE()) instead.
datename is what you would use to get the name of a month or weekday.
Or you could use the year(getdate()) function instead as Gordon L mentioned in a comment.
I'd recommend to switch back from fixing specific error message to the original question. You have a date in your table and need to filter it by range. So just provide to server the range bounds. This will also avoid any conversions of stored data. To avoid tail time issue you may append '23:59:59.997' to the upper bound of range or (my advice) provide next date and compare by < instead of <=
set #startdate = ...
set #enddate = dateadd(dd, 1, ...)
select *
from mytable
where t.date >= #startdate and t.date < #enddate
Complicated conversions can make it impossible to use appropriate index. If you can convert your arguments and provide prepared values to server - strive to do so.

Convert date in millisecond to date

In my table, I have a column that contains date in millisecond like this:
table a
dateinmili
1440301846096 //first six month date
1443589721039 //second six month date
I use that for my Android device and it works fine. When I want to use this time in a PROCEDURE in SQL Server and convert this time to human time (understandable for human) and date I have a problem.
I'm in Iran which uses UTC time in first six Persian date month 4.30 and 3.30 in second six month.
For convert date in PROCEDURE I use this code:
CONVERT(nVARCHAR(10),DATEADD(mi, DATEDIFF(mi, GETUTCDATE(), GETDATE()), DATEADD(ss,dateinmili/1000,'1970-01-01')),8) as date
DATEADD(mi, DATEDIFF(mi, GETUTCDATE(), GETDATE()), DATEADD(ss,dateinmili/1000,'1970-01-01')) as time
and here is my problem:
When I convert date in second six month and date registered in first six month of year, I get 1 hour difference between real time and converted time. I know that is because
DATEDIFF(mi, GETUTCDATE(), GETDATE())
method which return different between UTC time and local time when ever its called (in my example return 3:30 not 4:30 ) but I don't know how can I fix that?
I can add column which contain current UTC time but I am looking for another way.
update
I see this question and it's not my problem convert long to date.
My problem is in my country UTC time is not constant in whole year and change between 3.30 and 4.30, for example I have date registered in first six month (Persian six month) like 1440271800000 and convert it now which we are in second six month (Persian six month) and use this code for convert.
declare #unixTS bigint
set #unixTS = 1440271800000
select dateadd(ms, #unixTS%(3600*24*1000),
dateadd(day, #unixTS/(3600*24*1000), '1970-01-01 03:30:00.0')
)
I get this
2015-08-22 23:00:00.000
but it's not right date; the right date is:
2015-08-23 00:00:00.000
because when time registered UTC was 4.30 and not 3.30 but know when I convert
it UTC is 3.30.
I wish if there was a method in SQL which return past UTC time different; I mean put a date to that and return that time different between local time and gmt time my problem solved.
I hope you understand my problem.
In the US we have Daylight Savings Time in the summer, in most areas that means that we are also not fixed offset from UTC. Older versions of MS Dynamics CRM used to save everything in UTC, so when we wanted to export data in local time, we had a similar exercise. I created a set of SQL functions that would take the standard GMT offset and the datetime to I wanted to convert and figure out whether to apply the standard or DST offset and return the local datetime. If your offset follows a set of rules, then you can modify this:
CREATE function [dbo].[DC_GMTtoLocal]
(#OrigGMT datetime,
#StandardOffset int)
RETURNS datetime
AS
BEGIN
DECLARE #RevDate datetime
set #RevDate = CASE dbo.DC_DaylightSavingTime_IsInEffect(#OrigGMT)
WHEN 1 THEN DATEADD(hour, - #StandardOffset + 1, #OrigGMT) -- in DST
ELSE DATEADD(hour, - #StandardOffset, #OrigGMT) -- Not In DST
END
return #RevDate
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE function [dbo].[DC_DaylightSavingTime_IsInEffect]
(#DtTime datetime)
RETURNS tinyint
AS
BEGIN
DECLARE #DLSStart datetime
, #DLSEnd datetime
, #DLSActive tinyint
SET #DLSActive = 0
If DATEADD(YEAR,3,GETDATE()) > #DtTime
BEGIN
SET #DLSStart =(SELECT dbo.DC_GetDaylightSavingsTimeStart(CONVERT(varchar,DATEPART(YEAR,#DtTime))))
SET #DLSEnd =(SELECT dbo.DC_GetDaylightSavingsTimeEnd(CONVERT(varchar,DATEPART(YEAR,#DtTime))))
IF #DtTime BETWEEN #DLSStart AND #DLSEnd
BEGIN
SET #DLSActive = 1
END
--SET #DLSActive = 0
END
RETURN #DLSActive
END
GO
CREATE function [dbo].[DC_GetDaylightSavingsTimeStart]
(#Year varchar(4))
RETURNS smalldatetime
as
--Start date: We evaluate the day of the week corresponding to the first day of the month and find the second Sunday of March using a Case statement
begin
declare #DTSStartWeek smalldatetime, #DTSEndWeek smalldatetime
set #DTSStartWeek = '03/01/' + convert(varchar,#Year)
return case datepart(dw,#DTSStartWeek)
when 1 then
dateadd(hour,170,#DTSStartWeek)
when 2 then
dateadd(hour,314,#DTSStartWeek)
when 3 then
dateadd(hour,290,#DTSStartWeek)
when 4 then
dateadd(hour,266,#DTSStartWeek)
when 5 then
dateadd(hour,242,#DTSStartWeek)
when 6 then
dateadd(hour,218,#DTSStartWeek)
when 7 then
dateadd(hour,194,#DTSStartWeek)
end
end
GO
CREATE function [dbo].[DC_GetDaylightSavingsTimeEnd]
(#Year varchar(4))
RETURNS smalldatetime
as
-- End date: We evaluate the day of the week corresponding to the first day of the month and find the first Sunday of March using a Case statement
begin
declare #DTSEndWeek smalldatetime
set #DTSEndWeek = '11/01/' + convert(varchar,#Year)
return case datepart(dw,dateadd(week,1,#DTSEndWeek))
when 1 then
dateadd(hour,2,#DTSEndWeek)
when 2 then
dateadd(hour,146,#DTSEndWeek)
when 3 then
dateadd(hour,122,#DTSEndWeek)
when 4 then
dateadd(hour,98,#DTSEndWeek)
when 5 then
dateadd(hour,74,#DTSEndWeek)
when 6 then
dateadd(hour,50,#DTSEndWeek)
when 7 then
dateadd(hour,26,#DTSEndWeek)
end
end
GO

SQL Server adding one month to a date represented as an 8 digit decimal

A SQL Server application we use (accpac) represents dates as an 8 digit decimal in ISO format (example: today's date is 20100802)
I need to add one month to this. I've found a way to do it, but there must be a better way.
The steps of my solution are:
declare #accpacDate as decimal
set #accpacDate = 20100101
declare #date1 as date
declare #date2 as date
set #date1=cast(CAST(#accpacDate as varchar(8)) as datetime) /*get the starting value as a date */
set #date2=DATEADD(month,1,#date1)
select CONVERT(varchar(8),#date2,112) as aVarchar
select convert(decimal,CONVERT(varchar(8),#date2,112)) as aDecimal
SELECT CONVERT(VARCHAR(8),DATEADD(MONTH,1,CONVERT(VARCHAR(8),20100802,112)),112)
It seems about right what you are doing.
String and Date manipulation is pretty core in SQL, no fancy wrappers for auto-converting and manipulating date formats (accpac, memories, shiver).
You could write that into a user function, to add days to a accpac date, and return the result:
create function accpacadd
( #accpacdate decimal,
#days int)
RETURNS decimal
AS BEGIN
declare #date1 as datetime
set #date1=cast(CAST(#accpacDate as varchar(8)) as datetime) /*get the starting value as a date */
set #date1=DATEADD(day, #days, #date1)
return convert(decimal, CONVERT(varchar(8), #date1, 112))
END
So then you can just call it with min code:
select dbo.accpacadd(20100102, 5)
select dbo.accpacadd(20100102, -5)
Gives 20100107 and 20091228 respectively

Resources