Subtracting Datetimes - sql

I'm trying to find the most simple way to subtract to DATETIMEs from each other to produce a difference in the format of YY:MM.
Concatenating DATEDIFF of the two periods by year and month clearly just combines the same time differences together so a time period that is 2 years apart shows 2yrs,24months, when I am hoping to get it to show 2yrs,0months.
DATEDIFF(y,startdate,GETDATE())
Any tips? Thanks! Using SQL Server.

You can do this by constructing it with CONCAT() using the DATEDIFF() results by the month:
Select Concat
(
Right('00' + Convert(Varchar, DateDiff(Month, StartDate, GetDate()) / 12), 2),
':',
Right('00' + Convert(Varchar, DateDiff(Month, StartDate, GetDate()) % 12), 2)
)

Select Concat(DateDiff(YY,StartDate,GetDate()),' Yrs,')+Concat((DateDiff(MM,StartDate,GetDate())) % 12,' months')
Returns
2 Yrs,2 months
-- Assuming StartDate is 2014-04-29

Related

Subtract one month from mm/yy in SQL

How can I subtract one month from mm/yy in SQL?
For an example from 02/23 to 01/23.
Since your date format is not the recommended one. But for your scenario, you can use the following query to get your expected result.
Using DATEFROMPARTS() and string functions you can construct as a date and the DATEADD(MONTH, -1, date) will help to subtract one month.
DECLARE #TestTable TABLE (DateVal VARCHAR(5));
INSERT INTO #TestTable (DateVal) VALUES ('02/23'), ('01/23'), ('03/30');
SELECT DateVal,
RIGHT(CONVERT(VARCHAR(8), DATEADD(MONTH, -1, DATEFROMPARTS(RIGHT(DateVal, 2), LEFT(DateVal, 2), '01')), 3), 5) AS Result
FROM #TestTable
Result:
DateVal Result
----------------------
02/23 01/23
01/23 12/22
03/30 02/30
Demo on db<>fiddle
I think you need to use convert() to get a valid date, then dateadd() to subtract 1 month and finally format() to get the date in the string format:
select
format(dateadd(month, -1, convert(date, concat('01/', datecolumnname), 3)), 'MM/yy')
from tablename
See the demo.
This comes with a warning is super ugly but if you want string previous month then string again, maybe convert to date do the dateadd then back to string, horrid!
with cte_d
as
(select '01/23' as stringdate
union
select '12/17' as stringdate
)
select stringdate
,cast(Month(dateadd(month,-1,cast(right(stringdate,2)
+ left(stringdate,2) + '01' as date))) as nvarchar(2))
+'/'+
right(cast(Year(dateadd(month,-1,cast(right(stringdate,2)
+ left(stringdate,2) + '01' as date))) as nvarchar(4)),2) as [NewDate]
from cte_d

how to Select getdate () in yyyy/M format

I want to select getdate() in the format yyyy/M. I tried to write a query
SELECT FORMAT(GETDATE(), 'yyyy/M')
but it is throwing an error.
I am a beginner in SQL. How do I get the yyyy/m format if there is only single digit month? E.g. the query should return 2016/1 when there is only one digit month (it should not return 2016/01) and should return 2016/10 when the month has two digits
How about getting the YEAR and MONTH part of the date and just concatenate them:
SELECT
CAST(DATEPART(YEAR, GETDATE()) AS VARCHAR(4)) + '/' +
CAST(DATEPART(MONTH, GETDATE()) AS VARCHAR(2))
Try this:
SELECT FORMAT(GETDATE(),'yyyy/MM')
SELECT FORMAT(CAST('2015-11-15' AS smalldatetime),'yyyy/M'),
FORMAT(CAST('2015-01-15' AS smalldatetime),'yyyy/M')
Gives:
2015/11 | 2015/1
SELECT CONVERT(VARCHAR(7), GETDATE(), 111) AS [YYYY/MM]
OR
SELECT CONVERT(VARCHAR(7), GETDATE(), 111)

Get 2 Digit Number For The Month

I have an integer column "Month"
I would like to get 2 digit number for month.
This is what I have tried: DATEPART(mm, #Date)
It returns one digit for months January to September
I am using SQL Server 2008
Anyone has suggestion?
Function
FORMAT(date,'MM')
will do the job with two digit.
there are different ways of doing it
Using RTRIM and specifing the range:
like
SELECT RIGHT('0' + RTRIM(MONTH('12-31-2012')), 2);
Using Substring to just extract the month part after converting the date into text
like
SELECT SUBSTRING(CONVERT(nvarchar(6),getdate(), 112),5,2)
see Fiddle
There may be other ways to get this.
Pinal Dave has a nice article with some examples on how to add trailing 0s to SQL numbers.
One way is using the RIGHT function, which would make the statement something like the following:
SELECT RIGHT('00' + CAST(DATEPART(mm, #date) AS varchar(2)), 2)
Another simple trick:
SELECT CONVERT(char(2), cast('2015-01-01' as datetime), 101) -- month with 2 digits
SELECT CONVERT(char(6), cast('2015-01-01' as datetime), 112) -- year (yyyy) and month (mm)
Outputs:
01
201501
CONVERT(char(2), getdate(), 101)
Alternative to DATEPART
SELECT LEFT(CONVERT(CHAR(20), GETDATE(), 101), 2)
SQLFiddle Demo
append 0 before it by checking if the value falls between 1 and 9 by first casting it to varchar
select case when DATEPART(month, getdate()) between 1 and 9
then '0' else '' end + cast(DATEPART(month, getdate()) as varchar(2))
For me the quickest solution was
DATE_FORMAT(CURDATE(),'%m')
Simply can be used:
SELECT RIGHT('0' + CAST(MONTH(#Date) AS NVARCHAR(2)), 2)
Try:
select right ('0'+convert(nvarchar(2), DATEPART(mm, getdate())),2 )
My way of doing it is:
right('0'+right(datepart(month,[StartDate]),2),2)
The reason for the internal 'right' function is to prevent SQL from doing it as math add - which will leave us with one digit again.
SELECT REPLACE(CONVERT(varchar, MONTH(GetDate()) * 0.01), '0.', '')

DATEDIFF in HH:MM:SS format

I need to calculate the total length in terms of Hours, Minutes, Seconds, and the average length, given some data with start time and end time.
For example the result must be something like 45:15:10 which means 45 hours 15 min 10 sec, or 30:07 for 30 min 07 sec.
We're using SQL Server 2008 R2 and the conversion failed when time is more than 24:59:59. Any idea of how I could do this?
For information, the columns in the table are Id, StartDateTime, EndDateTime, etc. I need to make a monthly report which contains the recordings count of the month, the total length of these records, and the average length. I'd like to know if there is an easy way to perform all of this.
You shouldn't be converting to time - it is meant to store a point in time on a single 24h clock, not a duration or interval (even one that is constrained on its own to < 24 hours, which clearly your data is not). Instead you can take the datediff in the smallest interval required (in your case, seconds), and then perform some math and string manipulation to present it in the output format you need (it might also be preferable to return the seconds to the application or report tool and have it do this work).
DECLARE #d TABLE
(
id INT IDENTITY(1,1),
StartDateTime DATETIME,
EndDateTime DATETIME
);
INSERT #d(StartDateTime, EndDateTime) VALUES
(DATEADD(DAY, -2, GETDATE()), DATEADD(MINUTE, 15, GETDATE())),
(GETDATE() , DATEADD(MINUTE, 22, GETDATE())),
(DATEADD(DAY, -1, GETDATE()), DATEADD(MINUTE, 5, GETDATE())),
(DATEADD(DAY, -4, GETDATE()), DATEADD(SECOND, 14, GETDATE()));
;WITH x AS (SELECT id, StartDateTime, EndDateTime,
d = DATEDIFF(SECOND, StartDateTime, EndDateTime),
a = AVG(DATEDIFF(SECOND, StartDateTime, EndDateTime)) OVER()
FROM #d
)
SELECT id, StartDateTime, EndDateTime,
[delta_HH:MM:SS] = CONVERT(VARCHAR(5), d/60/60)
+ ':' + RIGHT('0' + CONVERT(VARCHAR(2), d/60%60), 2)
+ ':' + RIGHT('0' + CONVERT(VARCHAR(2), d % 60), 2),
[avg_HH:MM:SS] = CONVERT(VARCHAR(5), a/60/60)
+ ':' + RIGHT('0' + CONVERT(VARCHAR(2), a/60%60), 2)
+ ':' + RIGHT('0' + CONVERT(VARCHAR(2), a % 60), 2)
FROM x;
Results:
id StartDateTime EndDateTime delta_HH:MM:SS avg_HH:MM:SS
-- ------------------- ------------------- -------------- ------------
1 2013-01-19 14:24:46 2013-01-21 14:39:46 48:15:00 42:10:33
2 2013-01-21 14:24:46 2013-01-21 14:46:46 0:22:00 42:10:33
3 2013-01-20 14:24:46 2013-01-21 14:29:46 24:05:00 42:10:33
4 2013-01-17 14:24:46 2013-01-21 14:25:00 96:00:14 42:10:33
This isn't precisely what you asked for, as it won't show just MM:SS for deltas < 1 hour. You can adjust that with a simple CASE expression:
;WITH x AS (SELECT id, StartDateTime, EndDateTime,
d = DATEDIFF(SECOND, StartDateTime, EndDateTime),
a = AVG(DATEDIFF(SECOND, StartDateTime, EndDateTime)) OVER()
FROM #d
)
SELECT id, StartDateTime, EndDateTime,
[delta_HH:MM:SS] = CASE WHEN d >= 3600 THEN
CONVERT(VARCHAR(5), d/60/60) + ':' ELSE '' END
+ RIGHT('0' + CONVERT(VARCHAR(2), d/60%60), 2)
+ ':' + RIGHT('0' + CONVERT(VARCHAR(2), d % 60), 2),
[avg_HH:MM:SS] = CASE WHEN a >= 3600 THEN
CONVERT(VARCHAR(5), a/60/60) + ':' ELSE '' END
+ RIGHT('0' + CONVERT(VARCHAR(2), a/60%60), 2)
+ ':' + RIGHT('0' + CONVERT(VARCHAR(2), a % 60), 2)
FROM x;
This query changes the delta column in the 2nd row in the above result from 0:22:00 to 22:00.
I slightly modified Avinash's answer as it may end with error if difference is too big. If you need only HH:mm:ss it is sufficient to distinguish at seconds level ony like this:
SELECT CONVERT(time,
DATEADD(s,
DATEDIFF(s,
'2018-01-07 09:53:00',
'2018-01-07 11:53:01'),
CAST('1900-01-01 00:00:00.0000000' as datetime2)
)
)
SELECT CONVERT(time,
DATEADD(mcs,
DATEDIFF(mcs,
'2007-05-07 09:53:00.0273335',
'2007-05-07 09:53:01.0376635'),
CAST('1900-01-01 00:00:00.0000000' as datetime2)
)
)
If you want to do averages, then the best approach is to convert to seconds or fractions of a day. Day fractions are convenient in SQL Server, because you can do things like:
select avg(cast(endtime - starttime) as float)
from t
You can convert it back to a datetime using the reverse cast:
select cast(avg(cast(endtime - starttime as float) as datetime)
from t
The arithmetic to get the times in the format you want . . . that is a pain. You might consider including days in the final format, and using:
select right(convert(varchar(255), <val>, 120), 10)
To get the hours exceeding 24, here is another approach:
select cast(floor(cast(<val> as float)*24) as varchar(255))+right(convert(varchar(255), <val>, 120), 6)
It uses convert for minutes and seconds, which should be padded with 0s on the left. It then appends the hours as a separate value.
Starting in SQL SERVER 2012, you don't need to use DATEDIFF function. You can use FORMAT function to achieve what you want:
SELECT
FORMAT(CONVERT(TIME, [appoitment].[Start] - [appointment].[End]), N'hh\:mm') AS 'Duration'
FROM
[tblAppointment] (NOLOCK)
A way that avoids overflows and can include days and go all the way to milliseconds in the output:
DECLARE #startDate AS DATETIME = '2018-06-01 14:20:02.100'
DECLARE #endDate AS DATETIME = '2018-06-02 15:23:09.000'
SELECT CAST(DATEDIFF(day,'1900-01-01', #endDate - #startDate) AS VARCHAR) + 'd ' + CONVERT(varchar(22), #endDate - #startDate, 114)
The above will return
1d 01:03:06:900
And, off course, you can use the formatting of your choice
SQL Supports datetime substraction which outputs a new datetime relative to the MIN date (for instance 1900-01-01, you can probably get this value from some system variable) This works better than DATEDIFF, because DATEDIFF will count ONE for each "datepart boundaries crossed", even if the elapsed time is less than a whole datapart. Another nice thing about this method is that it allows you to use the date formatting conversions.
If days is the (positive) number of days, like 0.5 for 12 hours, use this expression to format it as a proper duration:
CONVERT(varchar(9), FLOOR(days * 24)) + RIGHT(CONVERT(char(19), CAST(days AS datetime), 120), 6)
Excel will understands values up to 9999:59:59 when pasted. There apply a custom format: [h]:mm:ss in the English version ([u]:mm:ss for Dutch).

Converting datetime format to 12 hour

I have this query
select CONVERT(varchar(5), tdate ,108) AS [Time] from table
which gives me the time in 24 hour format( military)
I wanted to convert it into a 12 hour format so i tried the query below
select SUBSTRING(CONVERT(VARCHAR, tdate, 100),13,2) + ':'
+ SUBSTRING(CONVERT(VARCHAR, tdate, 100),16,2) + ''
+ SUBSTRING(CONVERT(VARCHAR, tdate, 100),18,2) AS T
from table
and i get the 12 hour format but I am just curious if there is a shorter or better way of doing it. any help?
If you want to convert the current datetime for example:
SELECT CONVERT(VARCHAR, getdate(), 100) AS DateTime_In_12h_Format
Instead of getdate() you can put your desired column in a query (such as tdate in your example). If you want JUST the time in 12h and not the date and time use substring/right to separate them. It seems that you already know how to =).
This page lists every datetime conversion. It's really handy if you need other types of conversions.
This will return just the time, not the date.
SELECT RIGHT(CONVERT(VARCHAR, getdate(), 100), 7) AS time
For your table data:
select RIGHT(CONVERT(varchar, tdate ,100), 7) AS [Time] from table
Below code will return only time like 10:30 PM
SELECT FORMAT(CAST(getdate() AS DATETIME),'hh:mm tt') AS [Time]
Get date of server
SELECT LTRIM(RIGHT(CONVERT(VARCHAR(20), GETDATE(), 100), 7))
or
If it is stored in the table
SELECT LTRIM(RIGHT(CONVERT(VARCHAR(20), datename, 100), 7))
Result:
11:41AM
ifnull(date_format(at.date_time,'%d/%m/%Y'),"") AS date_time,
ifnull(time_format(at.date_time ,'%h:%i:%s'),"") AS date_time
This is how a SQL procedure looks...(for separating date and time)..there is no need of a special column for time/date....
Note:if H instead of h it will show the "hour in 24 hour" format