Subtract Two Date Time Values in SQL Server - sql

I want to subtract two DateTime values:
I have Start DateTime #2015-06-14 23:00:00# End Date Time #2015-06-15 01:01:00#
I want to get the duration by time format like HH:MM:SS and update it in the duration column. I tried the following code but, it doesn't work.
update [ZainJTA].[dbo].[TBL_Justification]
set [Justification_Event_Duration]=CONVERT(Datetime,(DateDiff("n",[Justification_From],[Justification_TO])/60/24),108)

DATEDIFF returns an INT, so dividing it by two other INTs is going to give you - another INT, most likely zero.
Try:
CONVERT(Datetime,(DateDiff(s,[Justification_From],[Justification_TO])/60.0/60/24),108)
(the 60.0 will trigger conversion to a floating point format.)
However, it'd probably make more sense to store it as a number of seconds (integer), and only do the CONVERT when you output it to display.
To display as just the time, with no day/year part, you'll also need to do a second conversion:
CONVERT(VARCHAR, CONVERT(Datetime,
(DateDiff(s,[Justification_From],[Justification_TO])/60.0/60/24),108),108)

Related

Calculate time difference in SQL

We have two columns in SQL. one is total_work_time & next is total_exeption_time & both column data type is varchar
total_work_time value is 07:15:00
total_exeption_time value is 01:15:00
So I need to subtract total_work_time - total_exeption_time and the result will be 06:00:00.
I have tried with concat(DATEDIFF(HOUR,total_exeption_time,total_work_time),':', DATEDIFF(MINUTE,total_exeption_time,total_work_time))
But the result is 6:360. from this, 360 is the problem, it taken total minutes. I need the result structure like 06:00:00. How to fix this issue using SQL Server.
You should be storing time values in a TIME datatype - using the correct datatype is not only a best practice but will reduce the problems you face in future.
You can convert your VARCHAR values to TIME and then use the following calculation which takes the difference in seconds (your lowest unit of interest one assumes) and creates a new TIME result.
DECLARE #total_work_time TIME = '07:15:00', #total_exeption_time TIME = '01:15:00';
SELECT CONVERT(TIME, DATEADD(SECOND, DATEDIFF(SECOND, #total_exeption_time, #total_work_time), '00:00'));

Get average of TIME(7)

ProcessTime: 00:00:00.0000012
RegexResolveTime: 00:00:00.0000421
MessageResolveTime: 00:00:00.0001269
FullProcessTime: 00:00:00.0001734
Ok, I've got 4 columns as above with datatype Time(7). I need to get the average of all the entries for those individual columns but Time(7) isn't a valid type for the AVG operator!
How does one go about getting the average of a Time(7) column?
I'll add that these are Timespans and not discrete points in time even though SQL server considers them such!
You can't average TIME because TIME represents a point in time, not a duration. I suggest one of two approaches.
The preferred approach: store duration as an integer in milliseconds, microseconds, nanoseconds, what have you. This will allow you much more precision if needed.
Apply conversions back and forth so you can average the delta from midnight instead of the actual time value.
DECLARE #x TABLE (ProcessTime TIME(7));
INSERT #x VALUES ('00:00:00.0000012'), ('00:00:00.0000016');
SELECT DATEADD(NANOSECOND, AVG(DATEDIFF(NANOSECOND, '00:00:00.0000000', ProcessTime)),
CONVERT(TIME, '00:00:00.0000000'))
FROM #x;
Results:
00:00:00.0000014
But doesn't that seem wrong to you? If you're not storing a point in time and you're only concerned about duration, store the duration. You can always format it as time when displaying.

SQL Calculations with HH:MM:SS

I have a column that comes into my SQL database as a varchar(10), but looks like HH:MM:SS. The column name is runTime.
I need to convert that column to seconds and do some calculations with it and another colunm called totalItems. totalItems is an int data type. An example of one calculation would be:
totalItems/runTime
So, it appears as though I need to convert runTime to a decimal, and then use it in the calculation, but when I can't do that without first converting the time to seconds, or I get an error (due to the ":").
So, how can I possibly convert the sessionRunTime into seconds first, and then convert those seconds to a decimal data type, then do the calculation from there? One example might be 59222 totalItems and 04:15:17 for runTime.
If there's a better way to handle this, I'm certainly open to that as well. Thanks!
So long as the hours portion doesn't match or exceed 24, you can convert to a datetime and use the built in functions to work out how long the time is in seconds:
select DATEDIFF(second,'00:00:00',CONVERT(datetime,'04:15:17'))
15317
If you need to do maths with this result, and the other value is an int, then multiple one or other of the values by 1.0 to force the maths to be done as floats, if that's required.
You can cast to datetime and use datediff to convert your string to seconds.
select datediff(second, 0, cast('04:15:17' as datetime))
Result:
15317

SQL Server 2005 DateTime math

I'm trying to get the amount of time spent on something. I have the DateTime for the start and end of the thing in two columns. I can do:
cnext.CreatedDate - c.CreatedDate
which results in something like this:
1900-01-01 00:00:19.190
which means they spent 19.19 seconds on the thing. That's great for each row but i would like to group by the specific thing and sum up the time spent on each thing:
SUM(cnext.CreatedDate - c.CreatedDate)
but I get a:
Operand data type datetime is invalid for sum operator.
How should i go about getting the total time is I can't sum up DateTime types?
You can't SUM datetime values. This is like taking the square root of a string.
Try:
SUM(DATEDIFF(SECOND, c.CreatedDate, cnext.CreatedDate))
Or if you want greater precision:
SUM(DATEDIFF(MILLISECOND, c.CreatedDate, cnext.CreatedDate))
If the date potion is 1/1/1900, convert the dates to floats, subtract them, and convert the result back to datetime.

Convert SQL server datetime fields to compare date parts only, with indexed lookups

I've been doing a convert(varchar,datefield,112) on each date field that I'm using in 'between' queries in SQL server to ensure that I'm only accounting for dates and not missing any based on the time part of datetime fields.
Now, I'm hearing that the converts aren't indexable and that there are better methods, in SQL Server 2005, to compare the date part of datetimes in a query to determine if dates fall in a range.
What is the optimal, indexable, method of doing something like this:
select * from appointments
where appointmentDate>='08-01-2008' and appointmentDate<'08-15-2008'
The best way to strip the time portion of a datetime field is using datediff and dateadd functions.
DateAdd(day, datediff(day,0, MydateValue), 0)
This takes advantedge of the fact that SQL Server stores dates as two integers, one representing the number of days since day "0" - (1 jan 1900), and the second one which represents the number of ticks (each tick is about 3.33 ms) since midnight (for the time) *.
the formula above simply has to only read the first integer. There is no conversion or processing required, so it is extremely fast.
To make your queries use an index... use this formula on the input filtering parameters first, or on the "other" side of the equal sign from the tables date time field, so that the query optimizer does not have to run the calculation on every datetime field in the table to determine which rows satisfy the filter predicate. This makes your search argument "SARG-able" (Search ARGument)
Where MyDateTimeColumn > DateAdd(day,
datediff(day,0, #MydateParameter), 0) -- SARG-able
rather than
Where DateAdd(day, datediff(day,0,
MyDateTimeColumn ), 0) > #MydateParameter -- Not SARG-able
* NOTE. Internally, the second integer (the time part) stores ticks. In a day there are 24 x 60 X 60 X 300 = 25,920,000 ticks (serendipitously just below the max value a 32 bit integer can hold). However, you do not need to worry about this when arithmetically modifying a datetime... When adding or subtracting values from datetimes you can treat the value as a fraction as though it was exactly equal to the fractional portion of a day, as though the complete datetime value was a floating point number consisting of an integer portion representing the date and the fractional portion representing the time). i.e.,
`Declare #Dt DateTime Set #Dt = getdate()
Set #Dt = #Dt + 1.0/24 -- Adds one hour
Select #Dt
Set #Dt = #Dt - .25 -- Moves back 6 hours
Select #Dt`
Converting numeric types to string values (a type of Boxing) is not the best performing method of doing what you are looking for. Its not really about index-able, because the actual column type is date time.
If you are looking for the best way query for dates, then your example is right, but you may want to take into account the 3 ms precision difference in MSSQL. It can mean that records from one day can show up in another day's result.
This
select * from appointments where appointmentDate>='08-01-2008' and appointmentDate<'08-15-2008'
Should be this
select * from appointments where appointmentDate>='08-01-2008' and appointmentDate<='08-14-2008 23:59:59.996'
It's correct - doing the conversion will execute the conversion for every row queried. It's better to leave the date columns as dates, and pass in your where clauses as dates:
select * from appointments where appointmentdate between
'08/01/2008' AND '08/16/2008'
Note: Leaving off the time means midnight (00:00.000), so you will include all times for 08/01, and all times from 08/15, and anything that is exactly 08/16/2008 00:00:00
Have a computed persisted column calculate the expression you need. If columns are computed and persisted, they can also be indexed.
There is also the way described at http://www.stillnetstudios.com/comparing-dates-without-times-in-sql-server/
SELECT CAST(FLOOR(CAST( getdate() AS float )) AS datetime)