I have a Login/Logout system that compute the total hours work of the employees. My problem is the formatting of the date&time difference for minutes.
Example:
if user logged-in 8:00 AM and logged-out 6:30 PM, the total should be 10.50 but my SQL output is 10 hrs and 30 mins. I know the formula(it should be 30mins/60 = 50) but I didn't know where should I put that Dividend(/60) on my SQL Query.(see below my SQL Code).
SQL Code:
SELECT *,CAST(Datediff(HOUR, 0, logout_time - login_time) +
Cast(Datediff(MINUTE, 0, logout_time - login_time) -
(Datediff(HOUR, 0, logout_time - login_time) * 60 ) AS DECIMAL) / 100 AS Decimal(18,2)) AS [TotalHrs_Worked]
FROM table_DTR
WHERE CONVERT(VARCHAR(10),log_date, 101) BETWEEN '09/01/2014' AND '11/30/2014'
If you simply take the minutes between a pair of datetime values and multiply it by 60.0 (with a decimal place so it produces a result with a decimal value), this should work without problem:
Run this example:
DECLARE #start DATETIME = '2014-12-15 08:00:00'
DECLARE #end DATETIME = '2014-12-15 18:30:00'
SELECT DATEDIFF(minute, #start, #end)/60.0 AS HoursWorked
This will produce:
10.50
You shouldn't need to break it down in to minutes and hours like you are doing in your SQL.
Related
In SQL server 2008, I would like to get datetime column rounded to nearest hour and nearest minute preferably with existing functions in 2008.
For this column value 2007-09-22 15:07:38.850, the output will look like:
2007-09-22 15:08 -- nearest minute
2007-09-22 15 -- nearest hour
declare #dt datetime
set #dt = '09-22-2007 15:07:38.850'
select dateadd(mi, datediff(mi, 0, #dt), 0)
select dateadd(hour, datediff(hour, 0, #dt), 0)
will return
2007-09-22 15:07:00.000
2007-09-22 15:00:00.000
The above just truncates the seconds and minutes, producing the results asked for in the question. As #OMG Ponies pointed out, if you want to round up/down, then you can add half a minute or half an hour respectively, then truncate:
select dateadd(mi, datediff(mi, 0, dateadd(s, 30, #dt)), 0)
select dateadd(hour, datediff(hour, 0, dateadd(mi, 30, #dt)), 0)
and you'll get:
2007-09-22 15:08:00.000
2007-09-22 15:00:00.000
Before the date data type was added in SQL Server 2008, I would use the above method to truncate the time portion from a datetime to get only the date. The idea is to determine the number of days between the datetime in question and a fixed point in time (0, which implicitly casts to 1900-01-01 00:00:00.000):
declare #days int
set #days = datediff(day, 0, #dt)
and then add that number of days to the fixed point in time, which gives you the original date with the time set to 00:00:00.000:
select dateadd(day, #days, 0)
or more succinctly:
select dateadd(day, datediff(day, 0, #dt), 0)
Using a different datepart (e.g. hour, mi) will work accordingly.
"Rounded" down as in your example. This will return a varchar value of the date.
DECLARE #date As DateTime2
SET #date = '2007-09-22 15:07:38.850'
SELECT CONVERT(VARCHAR(16), #date, 120) --2007-09-22 15:07
SELECT CONVERT(VARCHAR(13), #date, 120) --2007-09-22 15
I realize this question is ancient and there is an accepted and an alternate answer. I also realize that my answer will only answer half of the question, but for anyone wanting to round to the nearest minute and still have a datetime compatible value using only a single function:
CAST(YourValueHere as smalldatetime);
For hours or seconds, use Jeff Ogata's answer (the accepted answer) above.
Select convert(char(8), DATEADD(MINUTE, DATEDIFF(MINUTE, 0, getdate), 0), 108) as Time
will round down seconds to 00
I am using the below to determine the minute between two times,
DateDiff(Minute, [MondayOpenTime] , [MondayCloseTime])
For a start time of 09:00 and a Close time of 17:30 it returns the value 510
Or if i use:
DateDiff(hour, [MondayOpenTime] , [MondayCloseTime])
It returns 8,
How do i get it to return the hours and minutes like 08:30
Using the minute, and then divide by 60, gives 8.5,
Note. I have been through many of the similar questions to this, if there is one with an exact answer i will delete this, but i cannot find any answers as of yet
You can calculate the hours by division as you stated. You can then use modulo to calculate the minutes.
declare #MondayOpenTime time = '09:00'
, #MondayCloseTime time = '17:30'
select convert(varchar(2), DateDiff(Minute, #MondayOpenTime , #MondayCloseTime) / 60) + ':' + right('0' + convert(varchar(2), DateDiff(Minute, #MondayOpenTime , #MondayCloseTime) % 60), 2)
For datetime(2) datatypes, the following could be used:
format([MondayCloseTime] - [MondayOpenTime], 'HH:mm')
Provided that the dates fall on the same day. (since these are opening times, that shouldn't be a problem)
As Sean pointed out: for time datatypes, subtraction isn't directly possible and an extra cast is needed:
format(cast([MondayCloseTime] as datetime) - cast([MondayOpenTime] as datetime), 'HH:mm')
(sidenote: format is only available on sql-server 2012 and higher)
I'm having a little trouble getting a count of dates in SQL SERVER. I require the number of calender days between 2 dates start and ends dates included. The problem with the example below is that it always returns 10 when I believe it should be 11.
DECLARE #FROM DATETIME, #TO DATETIME
SET #FROM = '18/12/2011 00:00:00'
SET #TO = '28/12/2011 00:00:00'
SELECT
DATEDIFF(MINUTE,#FROM,#TO), -- Returns 14459
DATEDIFF(HOUR,#FROM,#TO), -- Returns 241
DATEDIFF(DAY,#FROM,#TO), -- Returns 10
CEILING(CAST((DATEDIFF(HOUR,#FROM,#TO) / 24) as DECIMAL(9,5))) --Returns 10
CEILING(CAST(CEILING(CEILING(CAST(DATEDIFF(SECOND,#FROM,#TO) as DECIMAL(18,5))) / 60) / 60 as DECIMAL(9,5)) / 24) --Returns 10
The bottom line works if there is at least 1 second between the times but I must account for all scenarios.
My only other thought was to simply add one to the date diff to account for the part days? Is that reliable?
DATEDIFF(DAY,#FROM,#TO) + 1
I came across when answering this question How to find the total between the dates for each values
Is an expression that can be resolved to a time, date, smalldatetime,
datetime, datetime2, or datetimeoffset value. date can be an
expression, column expression, user-defined variable or string
literal. startdate is subtracted from end date.
This is taken from MSDN here.
28-18 = 10. I think you will always have to add 1 in the scenario you have because of the definition for DATEDIFF.
You need to set the #TO date to:
SET #TO = '28/12/2011 23:59:59'
To get the number of days between two dates (ignoring the time of day), including the start and end date, try;
SELECT FLOOR(CONVERT(FLOAT, #TO))-FLOOR(CONVERT(FLOAT, #FROM))+1
Edit:
SELECT DATEDIFF(d, #FROM, #TO)+1
seems to return the exact same results, which would indeed make it a more elegant way of doing it. Always thought DATEDIFF timeparts were about truncating after the calculation (which would give the wrong result if the start time was later in the day than the end time) and not truncating before the calculation which gives the correct result for your case. You learn something new every day :)
If you want a close equivalent of the C# DateTime.TotalDays() function (i.e. to know fractional days) you can use the following:
DECLARE #start DATETIME = '10 Apr 2012 15:00'
DECLARE #end DATETIME = '12 Apr 2012 16:00'
SELECT CONVERT(FLOAT, DATEDIFF(SECOND, #start, #end)) / 86400
*Note: 86400 = seconds in a day = 24 hours x 60 mins x 60 seconds
When using the mssql script generation with data the datetime is exported with a cast:
CAST(0x00009E0E0095524F AS DateTime)
Does anyone know what format is used ?
The date in the example is shown as 2010-10-13 09:03:39.783.
Upper 4 bytes = days from 01 Jan 1900, lower 4 = time of day
It's the internal storage of datetime which is 8 bytes as two 4 byte integers, one with whole days, the other as fraction of day.
DECLARE #inttop bigint, #TheValue bigint
SET #inttop = POWER(CAST(2 AS bigint), 32)
SET #TheValue = CAST(0x00009E0E0095524F AS bigint)
SELECT
--days since 01 Jan 1900
#TheValue / #inttop,
--fractional time of day
CAST(#TheValue % #inttop AS float) / #inttop
--and confirm it
SELECT
DATEADD(DAY, #TheValue / #inttop, 0),
CAST(CAST((#TheValue % #inttop) AS float) / #inttop AS datetime)
I have to calculate the difference in hours (decimal type) between two dates in SQL Server 2008.
I couldn't find any useful technique to convert datetime to decimal with 'CONVERT' on MSDN.
Can anybody help me with that?
UPDATE:
To be clear, I need the fractional part as well (thus decimal type). So from 9:00 to 10:30 it should return me 1.5.
DATEDIFF(hour, start_date, end_date) will give you the number of hour boundaries crossed between start_date and end_date.
If you need the number of fractional hours, you can use DATEDIFF at a higher resolution and divide the result:
DATEDIFF(second, start_date, end_date) / 3600.0
The documentation for DATEDIFF is available on MSDN:
http://msdn.microsoft.com/en-us/library/ms189794%28SQL.105%29.aspx
Just subtract the two datetime values and multiply by 24:
Select Cast((#DateTime2 - #DateTime1) as Float) * 24.0
a test script might be:
Declare #Dt1 dateTime Set #Dt1 = '12 Jan 2009 11:34:12'
Declare #Dt2 dateTime Set #Dt2 = getdate()
Select Cast((#Dt2 - #Dt1) as Float) * 24.0
This works because all datetimes are stored internally as a pair of integers, the first integer is the number of days since 1 Jan 1900, and the second integer (representing the time) is the number of (1) ticks since Midnight. (For SmallDatetimes the time portion integer is the number of minutes since midnight). Any arithmetic done on the values uses the time portion as a fraction of a day. 6am = 0.25, noon = 0.5, etc... See MSDN link here for more details.
So Cast((#Dt2 - #Dt1) as Float) gives you total days between two datetimes. Multiply by 24 to convert to hours. If you need total minutes, Multiple by Minutes per day (24 * 60 = 1440) instead of 24...
NOTE 1: This is not the same as a dotNet or javaScript tick - this tick is about 3.33 milliseconds.
DATEDIFF but note it returns an integer so if you need fractions of hours use something like this:-
CAST(DATEDIFF(ss, startDate, endDate) AS decimal(precision, scale)) / 3600
Using Postgres I had issues with DATEDIFF, but had success with this:
DATE_PART('day',(delivery_time)::timestamp - (placed_time)::timestamp) * 24 +
DATE_PART('hour',(delivery_time)::timestamp - (placed_time)::timestamp) +
DATE_PART('minute',(delivery_time)::timestamp - (placed_time)::timestamp) / 60
which gave me an output like "14.3"
You are probably looking for the DATEDIFF function.
DATEDIFF ( datepart , startdate , enddate )
Where you code might look like this:
DATEDIFF ( hh , startdate , enddate )
DATEDIFF(minute,startdate,enddate)/60.0)
Or use this for 2 decimal places:
CAST(DATEDIFF(minute,startdate,enddate)/60.0 as decimal(18,2))
Declare #date1 datetime
Declare #date2 datetime
Set #date1 = '11/20/2009 11:00:00 AM'
Set #date2 = '11/20/2009 12:00:00 PM'
Select Cast(DateDiff(hh, #date1, #date2) as decimal(3,2)) as HoursApart
Result = 1.00
SELECT DATEDIFF(hh, firstDate, secondDate)
FROM tableName
WHERE ...