SQL Server DateTime format from automatic export script - sql-server

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)

Related

Using between on a datepart with both hour and minute

I have a time field called Epoch that I know how to pull data from 6 to 8 AM out of. I do not know how to do that for 6:30 to 8:30, since datepart is hour or minute not both. Here is the code I have thus far.
select tmc_code, avg(speed) as AVGS
from [dbo].[CEAR_FULL_NONULL_CARS_3_12]
where epoch between (datepart(hour, epoch) = 6 and datepart(minute, epoch) = 30) and (datepart(hour, epoch) = 8 and datepart(minute, epoch) = 25)
group by TMC_Code order by tmc_code
Assuming Epoch is a datetime, perhaps convert to a TIME
Declare #YourTable table (epoch datetime)
Insert into #YourTable values
('2020-01-22 07:22:18')
,('2020-01-22 10:45:00')
Select *
From #YourTable
Where convert(time,epoch) between '06:30' and '08:30'
Returns
epoch
2020-01-22 07:22:18.000

SQL - Number of minutes in a month given month number

I have a MS SQL table which contains a column containing month numbers (stored as an int).
I would like to get the number of minutes in the month using the month number.
After looking through Stack Overflow I came across the following code which I thought I could adapt to tell me the number of minutes by replacing the word DAY with MINUTE but to no avail.
DECLARE #ADate DATETIME
SET #ADate = GETDATE()
SELECT DAY(EOMONTH(#ADate)) AS DaysInMonth
The month is a 1 or 2 digit int depending on the month.
UPDATE:
I do have the year as well stored in another column.
Use DATEDIFF with MINUTE.
IF OBJECT_ID('tempdb..#Month') IS NOT NULL
DROP TABLE #Month
CREATE TABLE #Month (
MonthNumber INT,
Year INT)
INSERT INTO #Month (
MonthNumber,
Year)
VALUES
(1, 2018),
(2, 2018),
(2, 2016), -- Leap
(12, 2018)
SELECT
M.MonthNumber,
M.Year,
FirstDay = DATEFROMPARTS(M.Year, M.MonthNumber, 1),
FirstDayNextMonth = DATEADD(
MONTH,
1,
DATEFROMPARTS(M.Year, M.MonthNumber, 1)),
Minutes = DATEDIFF(
MINUTE,
DATEFROMPARTS(M.Year, M.MonthNumber, 1), -- FirstDay
DATEADD(MONTH, 1, DATEFROMPARTS(M.Year, M.MonthNumber, 1))) -- FirstDayNextMonth
FROM
#Month AS M
Results:
MonthNumber Year FirstDay FirstDayNextMonth Minutes
1 2018 2018-01-01 2018-02-01 44640
2 2018 2018-02-01 2018-03-01 40320
2 2016 2016-02-01 2016-03-01 41760
12 2018 2018-12-01 2019-01-01 44640
That's a deceptively tricky question. It's not only that the number of days in February changes in leap years. The number of hours in a date changes during the transition to Summer/Winter time. To calculate the correct difference in minutes between two dates you need to know the correct time offset as well.
Instead of looking up the offset for each date though, you can use the timezone. The timezone information contains all the rules needed to calculate the time offset for past and future dates, provided the OS's timezone information is kept up to date.
SQL Server 2016 and later support timezones with the AT TIME ZONE expression :
For example these queries:
select datetimefromparts(2018,3,25,0,0,0,0) at TIME ZONE 'E. Europe Standard Time'
select datetimefromparts(2018,3,26,0,0,0,0) at TIME ZONE 'E. Europe Standard Time'
Return
2018-03-25 00:00:00.000 +02:00
2018-03-26 00:00:00.000 +03:00
March 25 had 23 hours instead of 24. The difference of the two days in minutes is 1380 instead of the usual 1440:
select datediff(mi,
datetimefromparts(2018,3,25,0,0,0,0) at TIME ZONE 'E. Europe Standard Time',
datetimefromparts(2018,3,26,0,0,0,0) at TIME ZONE 'E. Europe Standard Time')
-----
1380
You can pass the timezone name as a parameter :
declare #mytimezone nvarchar(40)='E. Europe Standard Time'
select datetimefromparts(2018,3,25,0,0,0,0) at TIME ZONE #mytimezone
select datetimefromparts(2018,3,26,0,0,0,0) at TIME ZONE #mytimezone
To calculate the correct number of minutes in a month, you could use the difference in minutes between the current and the next month's 1st day on a specific timezone with AT TIME ZONE. This would ensure the correct offsets are used.
A query that calculates the difference in minutes correctly could look like this :
declare #mytimezone nvarchar(40)='E. Europe Standard Time'
select year,month,
datediff(mi,
datetimefromparts(M.Year,M.Month,1,0,0,0,0) at TIME ZONE #mytimezone,
dateadd(MONTH,1,datetimefromparts(M.Year,M.Month,1,0,0,0,0)) at TIME ZONE #mytimezone
)
from (values
(2016,2),
(2018,1),
(2018,2),
(2018,3),
(2018,4),
(2018,5),
(2018,6),
(2018,7),
(2018,8),
(2018,9),
(2018,10),
(2018,11),
(2018,12) ) M(Year,Month)
You can create a function to calculate the minutes. Either a scalar function that can be used in the SELECT clause :
CREATE FUNCTION MinutesInMonth
(
#Year INT,
#Month INT,
#timezone nvarchar(40)
)
RETURNS INT
AS
BEGIN
Return
datediff(mi,
datetimefromparts(#year,#month,1,0,0,0,0) at TIME ZONE #timezone,
dateadd(MONTH,1,datetimefromparts(#year,#month,1,0,0,0,0)) at TIME ZONE #timezone
)
END
...
select year,month,dbo.MinutesInMonth(year,month,#mytimezone)
from (values
(2018,10),
(2018,11),
(2018,12)
) M(Year,Month)
Or an inline table function that can be used in the FROM clause and gets inlined in the query itself :
CREATE FUNCTION MinutesInMonth
(
#Year INT,
#Month INT,
#timezone nvarchar(40)
)
RETURNS TABLE
RETURN (select datediff(mi,
datetimefromparts(#year,#month,1,0,0,0,0) at TIME ZONE #timezone,
dateadd(MONTH,1,datetimefromparts(#year,#month,1,0,0,0,0))
At TIME ZONE #timezone) as Minutes
)
select year,month,Minutes
from (values
(2016,2),
(2018,1),
(2018,2),
(2018,3),
(2018,4),
(2018,5),
(2018,6),
(2018,7),
(2018,8),
(2018,9),
(2018,10),
(2018,11),
(2018,12)
) M(Year,Month)
cross apply dbo.MinutesInMonth(year,month,#mytimezone)
Try this out :-
DECLARE #Year INT = 2016, #Month INT = 2;
DECLARE #Date DATE = DATETIMEFROMPARTS(#Year,#Month, 1, 0, 0, 0, 0) AT TIME ZONE 'Sri Lanka Standard Time';
SELECT DAY(EOMONTH(#Date)) * 24 * 60;
Alternatively you can create a scalar function as follows:-
CREATE FUNCTION GetMinutesOfMonth
(
#Year INT,
#Month INT,
#TimeZone VARCHAR(50) = NULL
)
RETURNS INT
AS
BEGIN
DECLARE #MinutesOfMonth INT, #CurrentTimeZone VARCHAR(50);
EXEC MASTER.dbo.xp_regread 'HKEY_LOCAL_MACHINE',
'SYSTEM\CurrentControlSet\Control\TimeZoneInformation',
'TimeZoneKeyName',#CurrentTimeZone OUT;
SET #TimeZone = ISNULL((SELECT [name] FROM SYS.time_zone_info WHERE [name] = #TimeZone), #CurrentTimeZone)
DECLARE #Date DATE = DATETIMEFROMPARTS(#Year, #Month, 1, 0, 0, 0, 0) AT TIME ZONE #TimeZone;
SELECT #MinutesOfMonth = DAY(EOMONTH(#Date)) * 24 * 60;
RETURN #MinutesOfMonth;
END
GO
and use it as:-
DECLARE #Year INT = 2016, #Month INT = 2;
SELECT dbo.GetMinutesOfMonth(#Year, #Month, 'Sri Lanka Standard Time');
If the timezone of the current machine is same as the dates being considered, you may use the function as follows:-
DECLARE #Year INT = 2016, #Month INT = 2;
SELECT dbo.GetMinutesOfMonth(#Year, #Month, DEFAULT);

date & time difference format

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.

DATEADD with part days

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

How to calculate difference in hours (decimal) between two dates in SQL Server?

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 ...

Resources