how is DateDiff implemented in Sql Server? - sql

I use the following code in my statement.
datediff(minute, visit.nexttime, visit.endtime)
the results varies.
I will show u a couple of results.
0:24:26 - 25
0:32:14 - 32
0:05:12 - 5
0:06:28 - 7
0:03:52 - 4
0:03:32 - 3
first one, 24 rounds up to 25 while there is only 26 seconds.
second one, 32 remains where the second is 14.
third one, 5 remains 5, fair enough.
fourth one, 6 rounds up to 7 while there are only 28 seconds.
fifth one, 3 round up to 4 coz of 52 seconds.
last one, 3 remains 3 even there r 32 seconds.
Why is that?
I use the following code to get my first column.
CONVERT(varchar(6), datediff(second, visit.nexttime, visit.endtime)/3600)
+ ':' +
RIGHT('0' + CONVERT(varchar(2), (datediff(second, visit.nexttime, visit.endtime) % 3600) / 60), 2)
+ ':' +
RIGHT('0' + CONVERT(varchar(2), datediff(second, visit.nexttime, visit.endtime) % 60), 2)
as 'Transaction Time'

I'm not actually familiar with SQL Server, however reading the documentation here i suspect i know why you are getting those results.
The return value is described as this:
Returns the count (signed integer) of
the specified datepart boundaries
crossed between the specified
startdate and enddate.
Since you specified minute for the datepart, I would expect this means the seconds are ignored and it just counts how many times the minute changes between the startdate and enddate.
eg.
If the startdate and enddate were 50 seconds apart in the same minute, it would return 0.
If the startdate and enddate were only 5 seconds apart but in different minutes, it would return 1.

Datediff is a bit strange and rather nonintuitive. And it works this way since old Sybase days.
In your case datediff(m, x, y) completly ignores the seconds.
You have the same problem when you try to calculate ages:
select datediff (y, '2010-12-31', '2011-01-01')
does't mean that the rounded difference is about 1 year, it only says that 1 new year happend.
To get the results you intend, you must take the difference at a more granular base, as you did using seconds.

Please refer to the MySql documentation. It should clarify this for you.
http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_datediff

Related

SQL. Convert datediff hours to dd.hh:mm:ss

I've got some code that generates hours between an oldest record in the table (MIN) and getdate(), and am using
CONVERT(CHAR(8),DATEADD(SECOND,DATEDIFF(SECOND,MIN(OLDESTRECORD),GETDATE()),0),108)
to get the HH:MM:SS, but when the hours is more than 24 hours it just shows the hours part. i.e. 30 hours difference shows as 6 hours... how do I get it to show dd.hh:mm:ss i.e. 1.06:00:00
watch out for the case where the 'time' in the start day has not been reached in the end date
select cast(DATEDIFF(SECOND,MIN(OLDESTRECORD),GETDATE()) / 86400 as varchar(4)) + '.' + CONVERT(CHAR(8),DATEADD(SECOND,DATEDIFF(SECOND,MIN(OLDESTRECORD),GETDATE()) % 86400 ,0),108)

TIMESTAMPDIFF Missing Days

Can someone explain to me why this returns only 360 days and not 365 days?
I expect it to not count the first day but, what about the other 4 days?
SELECT
(TIMESTAMPDIFF(16,CHAR(TIMESTAMP('2017-12-31') - TIMESTAMP('2017-01-01'))))
FROM sysibm.sysdummy1
I am planning on just adding + 5 at the end.
If you have DB2 for Linux, Unix and Windows - now called Db2 - Version 11.1 you could also use
SELECT DAYS_between('2017-12-31','2017-01-01') FROM SYSIBM.SYSDUMMY1
I think the documentation explains this pretty well:
The returned estimate may vary by a number of days. For example, if
the number of days (interval 16) is requested for the difference
between '1997-03-01-00.00.00' and '1997-02-01-00.00.00', the result is
30. This is because the difference between the timestamps is 1 month, and the assumption of 30 days in a month applies.
In other words, the difference is 11 months and 30 days -- 11 * 30 + 30 = 360.
SELECT DAYS(DATE('2017-12-31')) - DAYS(DATE('2017-01-01'))
FROM sysibm.sysdummy1
For a more exact representation, try:

sql statement - would like to subtract 1 date from another and get the days hours and mins inbetween

I would like to subtract 1 date from another and get the days hours and mins in-between.
I know there is a DateDiff function, however it does not work with all 3 time values; days hours and mins. I would like this doable in an SQL statement. Currently I have the following.
SELECT id, pickupdateandtime, GETDATE() AS CurrentTime,
(DATEDIFF(day,GETDATE(),pickupdateandtime)) AS Days,
(DATEDIFF(hour,GETDATE(),pickupdateandtime)) AS Hours,
(DATEDIFF(minute,GETDATE(),pickupdateandtime)) AS Mins FROM orders
And it shows up like this:
If we can stick it all in 1 column that's fine too.
I agree with #AndyMcLaughlin about the use of the mod operator % here. It's very handy for this sort of thing. However, I have a general distrust of DATEDIFF. That function does not count the whole number of years (say) between two dates, but the number of year boundaries between them.
So DATEDIFF "thinks" the difference in years between 01-Jan-2000 and 01-Jan-2001 is the same as that between 31-Dec-2000 and 01-Jan-2001.
This is why #Michael saw a need to subtract 1 from #AndyMcLaughlin's results. Unfortunately, that doesn't always work, it will depend on the individual case.
As a rule, DATEDIFF works well when it's used against the smallest interval you are interested in. So if you are interested in years and simply want to separate one calendar year from another, it'll serve you well.
I think the smallest interval we are interested in here is minutes. So we can use DATEDIFF for that, but have to work upwards from there to hours and days:
select
mf.id,
mf.pickupdateandtime,
mf.CurrentTime,
--The divisions in the following lines simply
--truncate since all the numbers are integers
--but that works in our favour here
(mf.MinutesFull/(60*24)) as Days,
(mf.MinutesFull/60) % 24 as Hours,
mf.MinutesFull % 60 as Minutes
from
(
select
id,
pickupdateandtime,
getdate() as CurrentTime,
datediff(minute, getdate(), pickupdateandtime) as MinutesFull
from #orders
) mf
You need to use the mod operator % to remove whole days from hours and whole hours from minutes.
So you can do something like:
SELECT
id,
pickupdateandtime,
GETDATE() AS CurrentTime,
(DATEDIFF(day,GETDATE(),pickupdateandtime)) AS Days,
(DATEDIFF(hour,GETDATE(),pickupdateandtime) % 24) AS Hours,
(DATEDIFF(minute,GETDATE(),pickupdateandtime) % 60) AS Mins FROM orders

How does this aggregated query find the correct values

I am having trouble understanding this code. It actually seems to work, but I don't understand how the correct value for activity year and month is "found" get the proper min and max? Or is it running all permutations getting the highest? This is very strange to me.
I do understand how the dateadd works, just not how the query is actually working on the whole. This may be a bad question since I don't actually need help solving a problem, just insight into why this works.
select
EmployeeNumber,
sum(BaseCalculation) as BaseCalculation,
min(dateadd(mm, (ActivityYear - 1900) * 12 + ActivityMonth - 1 , 0)) as StartDate,
max(dateadd(mm, (ActivityYear - 1900) * 12 + ActivityMonth - 1 , 0)) as EndDate
from
Compensation
where
1=1
-- and
group by
EmployeeNumber
for both the min and max function call, the algorithm is
dateadd(mm, (ActivityYear - 1900) * 12 + ActivityMonth - 1 , 0)
Your query compute all possible date from the Compensation table using this algorithm. Then, you select the minimum date as StartDate and the maximum as EndDate.
This is how the proper max and min are returned.
Note that the dateadd signature is DATEADD (datepart , number , date )
Since the last parameter is 0, you are addind to month(mm) the number calculated in the algorithm, and return the corresponding date starting from 0.
Check this out for more information : https://msdn.microsoft.com/en-us/library/ms186819.aspx
It is converting the columns ActivityYear and ActivityMmonth to a date. It is doing so by counting the number of months since 1900 and adding them to time zero. So, Jan 2000 would become something like Jan, 100. This seems like a very arcane calculation, because dates that are about 2,000 years old are not really useful.
Of course, this assumes that ActivityYear is a recognizable recent year.
I would convert the year and month to the first day of the beginning of the month, with something like this:
min(cast(cast(ActivityYear * 10000 + ActivityMonth + 1 as varchar(255)) as date)
Sql Server will calculate every value of that statement, and then only return the min and max.
Although I cannot say for sure that sql server executes this way internally, the way I think about it I imagine that the engine strips off the group by and all the aggregate functions, runs that query. And then just sums/finds the min etc off of that.

SQL Subtracting OverNight Time (returning only minutes) Get rid of negative time?

I have a bunch of start and end times:
Start End Delta
20:47:22 22:47:02 120
22:49:12 0:48:47 -1321
0:50:42 2:50:22 120
...
23:11:07 2:10:44 -1261
The code I use is as follows (as time is a varchar)
CONVERT(VARCHAR(8), DATEDIFF(minute, max(max_time), min(min_time)) ,114)
as delta_time,
But as you can see, because it is overnight the result is negative. Any thoughts about getting the right result of 119 minutes and 179 minutes (in the example above).
I thought of using a case statement that checks when the delta is negative. If it is negative, add 24 hours to the End time then try the subtracting.
CASE WHEN DATEDIFF(minute, max(max_time), min(min_time)) < 0 THEN
DATEADD(minute, 1440, min(min_time))
ELSE 0 END AS deltatest
However this code doesn't work, as SQL Server just changes the time to: 1900-01-02 00:48:47.000 (the next day, not something like 24:48:47, which is what I want). Any thoughts? Is there any method to add a convert to the CASE statement?? Thanks.
You could always add 1440 to all of the computed deltas, then take the value mod 1440:
SELECT (120 + 1440) % 1440, (-1321 + 1440) % 1440
Result:
----------- -----------
120 119