How SQL's convert function work when converting datetime to float? - sql

why the out put of this query:
declare #currentDate as datetime
set #currentDate ='01/07/2010'
select convert(float, #currentdate)
...is 40183 ?
So for those who are getting confuse with my question, my question is How to know the result of above query without executing it ?

DateTime is often represented as a day count from a pre-determined date (generally know as the epoch) on the integer part and the percentage of the day elapsed since mid-night on the fractional part.
SQL Server is not the exception to this, thus the conversion to Float makes a lot of sense. Day 0 is Jan 01 1900 00:00:00 (AFAIK, in no particular time-zone, so you shall consider it "local time").
So, you can try this:
declare #ADate DateTime;
set #ADate = '19000101 00:00:00';
select CONVERT(float, #ADate); --should print 0
set #ADate = '19000101 12:00:00';
select CONVERT(float, #ADate); --should print 0.5
set #ADate = '19001231 06:00:00';
select CONVERT(float, #ADate); --should print 364.25
So, for your results, 40183 days has been passed since 01/01/1900 00:00:00 and 01/07/2010 00:00:00
Clarification: Unix like systems use a different approach to store datetimes: Seconds since Unix epoch (Jan 1 1970 00:00:00 UTC), which is more known as epoch time.
[Edit]
Date format on this response was changed to YYYYMMDD format on 20140416, after some new years of experience with SQL Server (and as #Damien said in his comment) this is the only safe format.

DateTime values are actually stored as two four-byte integers under the hood. The first four-byte integer represents the number of days since 1900-01-01. The second four-byte integer stores the number of milliseconds since midnight. When you convert a datetime into a float, the decimal portion represents the percentage of the 24-day that has past. Thus, 0.5 represents noon.

It's basically converting the datetime to an OLE Date. There's a decent description of the process in the documentation for System.DateTime.ToOADate():
http://msdn.microsoft.com/en-us/library/system.datetime.tooadate.aspx
The quick explanation is that the integer part is the number of days since 12/30/1899. The fractional part (zero in this case) is the time divided by 24.

This should help you understand the TSQL implementation (or implement your own):
DECLARE
#date DATETIME = '20180125 09:15:30.549',
#date_dec DECIMAL (26,10) = 43123.3857702546
SELECT
CAST(#date_dec AS DATETIME) AS [TSQL cast to DATETIME],
CAST(#date AS DECIMAL (26,10)) AS [TSQL cast to DECIMAL]
SELECT
DATEADD(DAY, FLOOR(#date_dec),
DATEADD(HOUR, FLOOR(#date_dec % 1 * 24),
DATEADD(MINUTE, FLOOR((#date_dec % 1 * 24) % 1 * 60),
DATEADD(SECOND, FLOOR(((#date_dec % 1 * 24) % 1 * 60) % 1 * 60),
DATEADD(MILLISECOND, FLOOR((((#date_dec % 1 * 24) % 1 * 60) % 1 * 60) % 1 * 1000), '19000101')
)
)
)
) AS [Manual cast to DATETIME],
DATEDIFF(DAY, '19000101', #date)
+ (
DATEPART(HOUR, #date)
+ (
DATEPART(MINUTE, #date)
+ (
DATEPART(SECOND, #date)
+ DATEPART(MILLISECOND, #date) / CAST(1000 AS FLOAT)
) / CAST(60 AS FLOAT)
) / CAST(60 AS FLOAT)
) / CAST(24 AS DECIMAL (26,10)) AS [Manual cast to DECIMAL]
Note that the result is not always the same as TSQL loses precision on last millisecond digit.

Related

Datediff function resulted in an overflow for two date Minute Diff (Without DateDiff_Big)

I am using SQL 2008/2012.
Query to calculate Minute Difference between two dates.
select DATEDIFF(mi, '9999-08-03 04:20:00.000', '2005-05-22 03:45:09.530')
Error:
The datediff function resulted in an overflow. The number of dateparts separating two date/time instances is too large. Try to use datediff with a less precise datepart.
Note : DateDiff_Big not support this version.
Is there any other way to get result. without using DateDiff_Big
So you use a smaller unit and do some arithmetic. But I presume you mean:
select datediff(minute, '2005-05-22 03:45:09.530', '9999-08-03 04:20:00.000')
Normally, one wants the difference to be positive (although that is not related to the answer).
select (convert(bigint, datediff(day, '2100-08-03 04:20:00', '9999-08-03 04:20:00.000')) * 60 * 24) +
datediff(minute, '2005-05-22 03:45:09.530', '2100-08-03 04:20:00')
Does this fit your needs
DECLARE #DT1 datetime = '9999-08-03 04:20:00.000'
DECLARE #DT2 datetime = '2005-05-22 03:45:09.530'
select --DATEDIFF_BIG(mi, #DT1, #DT2),
CONVERT(BIGINT, DATEDIFF(DAY, #DT1, #DT2)) * 24 * 60
+ CONVERT(BIGINT, DATEDIFF(mi, CONVERT(TIME(7), #DT1), CONVERT(TIME(7), #DT2)))
GO
try this type to get Minutes Different
SELECT CONVERT(BIGINT, DATEDIFF(HOUR, '2005-05-22 03:45:09.530', '9999-08-03 04:20:00.000')) * 60
Check This.
SELECT
CAST(DATEDIFF(hour, '9999-08-03 04:20:00.000', '2009-05-22 03:45:09.530') AS BIGINT)* 60+
DATEDIFF(mi, CONVERT(TIME, '9999-08-03 04:20:00.000'),
CONVERT(TIME, '2009-05-22 03:45:09.530'))+60;
DATEDIFF has a limit that depends on what time element is used.
Because it can only return a number that fits in an INT.
For a return value out of range for int (-2,147,483,648 to
+2,147,483,647), DATEDIFF returns an error. For millisecond, the maximum difference between startdate and enddate is 24 days, 20 hours,
31 minutes and 23.647 seconds. For second, the maximum difference is
68 years.
For minutes that appears to be 4083 years.
So then limit for minutes would be in the -4083 years to 4083 years range.
Then you could wrap the DATEDIFF in a CASE WHEN that checks if it's in that range.
And let it default to the DATEDIFF in hours * 60.
It'll loose some minutes for the default, but that might still be better than returning a NULL.
SELECT dt1, dt2,
DATEDIFF(year, dt1, dt2) AS diff_years,
DATEDIFF(hour, dt1, dt2) AS diff_hours,
CONVERT(BIGINT,
CASE
WHEN DATEDIFF(year, dt1, dt2) BETWEEN -4083 AND 4083
THEN DATEDIFF(minute, dt1, dt2)
ELSE CONVERT(BIGINT,DATEDIFF(hour, dt1, dt2)) * 60
END) AS diff_minutes
FROM (VALUES
('9999-08-03 04:20:00.000', '2005-05-22 03:45:09.530'),
('6083-01-01 00:00:00.000', '2000-01-01 00:00:00.000'),
('2000-01-01 00:00:00.000','6083-01-01 00:00:00.000'),
('0001-01-01 00:00:00.000','9999-12-31 00:00:00.000')
) q(dt1, dt2)

Convert Julian Date to YYYY-MM-DD

I have searched far and wide, but I can't seem find a way to convert julian to yyyy-mm-dd.
Here is the format of my julian:
The Julian format consists of the year, the first two digits, and the day within the year, the last three digits.
For example, 95076 is March 17, 1995. The 95 indicates the year and the
076 indicates it is the 76th day of the year.
15260
I have tried this but it isn't working:
dateadd(d,(convert(int,LAST_CHANGED_DATE) % 1000)-1, convert(date,(convert(varchar,convert(int,LAST_CHANGED_DATE) /1000 + 1900) + '/1/1'))) as GrgDate
You can select each part of the date using datepart()
SELECT DATEPART(yy, 95076), DATEPART(dy, 95076)
+++EDIT: I misunderstood something. Here's my correction: +++++
SELECT DATEADD(day, CAST(RIGHT('95076',3) AS int) – 1, CONVERT(datetime,LEFT('95076',2) + '0101', 112))
Edit: leaving this answer for Oracle and MySQL users
This will not work in T-SQL.
Use this:
MAKEDATE(1900 + d / 1000, d % 1000)
For example:
SELECT MAKEDATE(1900 + 95076 / 1000, 95076 % 1000)
This returns March, 17 1995 00:00:00.
SQLFiddle
I concatenated 20 to my JD and then ran
DATEADD(YEAR, LAST_CHANGE_DATE / 1000 - 1900, LAST_CHANGE_DATE % 1000 - 1)
this got me the result. Thank you!!!
FOR SQL Users
DECLARE #jdate VARCHAR(10)
SET #jdate = 117338
SELECT dateadd(dd, (#jdate - ((#jdate/1000) * 1000)) - 1, dateadd(yy, #jdate/1000, 0))
This will definitely work in all case.
DECLARE #date int
SET #date = 21319
SELECT DATEADD(dd, RIGHT(#date,LEN(#date)-3)-1, DATEADD(yy,LEFT(#date,1)*100 +RIGHT(LEFT(#date,3),2),'1 Jan 1900'))
You need to specify 1 or 0 for century in first character. For example, SET #date = 21319 should be prefixed with 1 or 0. Below is an example that will work with all y2k use cases.
DECLARE #jdate INT
SET #jdate = 119150
SELECT DATEADD(dd, (#jdate - ((#jdate/1000) * 1000)) - 1, DATEADD(yy, #jdate/1000, 0))
Declare #Julian varchar(7)
Declare #date date
Set #Julian = 2020277
Set #Date = Dateadd(day,+ Cast(right(#Julian,3) as int)-1, Cast(left(#Julian,4) + '0101' as Date))
Select #Date
Standard SQL is simple (you can do similar for 2 digit year YYMMDD)
Declare #julDate int = 2020275
Select
DateAdd
(
day
, Right(#julDate,3)-1
, Cast((Left(#julDate,4)+'-01-01') as smalldatetime)
)
Try this out:
DECLARE #jdate int
SET #jdate = 21243
select dateadd(dd, (#jdate - ((#jdate/1000) * 1000)) - 1, dateadd(yy, #jdate/1000+100, 0))

arithmetic operation on time datatype sql server?

I have a column "Time" with Time as its Datatype.
I need to get 25% of the value in that column.
Please help. I've been banging my head on the wall for the solution.
You need to convert TIME to float value. According to Data type conversion table you can do it through DATETIME, so:
DECLARE #d time = '03:00:00';
SELECT CONVERT(float, CONVERT(datetime, #d)) * 0.25 -- this will be 25% of the value in float
And then do reverse conversion:
DECLARE #f float = 0.03125; -- this is result of previous select.
SELECT CONVERT(time, CONVERT(datetime, #f)) -- Result = 00:45:00
So, in your query it will be:
SELECT ResultTime = CONVERT(time, CONVERT(datetime, (CONVERT(float, CONVERT(datetime, TimeColumn)) * 0.25)))
FROM Table
See DEMO
declare #time NUMERIC
set #TIME=(select cast(replace(replace(cast(cast(getdate() as time) as varchar),':',''),'.','') as NUMERIC)*.25)
IF LEN(#TIME)=12 BEGIN
SELECT '0'+SUBSTRING(CAST(#TIME AS VARCHAR(20)),0,2)+':'+SUBSTRING(CAST(#TIME AS VARCHAR(20)),3,2)+':'+SUBSTRING(CAST(#TIME AS VARCHAR(20)),5,2)+'.'+SUBSTRING(CAST(#TIME AS VARCHAR(20)),7,13)
END
ELSE
SELECT SUBSTRING(CAST(#TIME AS VARCHAR(20)),0,2)+':'+SUBSTRING(CAST(#TIME AS VARCHAR(20)),3,2)+':'+SUBSTRING(CAST(#TIME AS VARCHAR(20)),5,2)+'.'+SUBSTRING(CAST(#TIME AS VARCHAR(20)),7,13)
Not sure it's the best answer you can get, but i did it in one query :
SELECT CONVERT(TIME,
CONVERT(DATETIME,
CONVERT(FLOAT,
CONVERT(DATETIME, field )) / 4))
Here's a fiddle : http://sqlfiddle.com/#!3/01b3f/7
This worked for me:
select convert(varchar, dateadd(s, datediff(s, '00:00:00' , t) * .25, '00:00:00'), 8)
SQLFiddle
Convert from the date to Float
DECLARE #d time =getdate()
print #d
SELECT CONVERT(float , CONVERT(datetime, #d)) * 0.25

Cast smalldatetime to real - results? SQL [duplicate]

why the out put of this query:
declare #currentDate as datetime
set #currentDate ='01/07/2010'
select convert(float, #currentdate)
...is 40183 ?
So for those who are getting confuse with my question, my question is How to know the result of above query without executing it ?
DateTime is often represented as a day count from a pre-determined date (generally know as the epoch) on the integer part and the percentage of the day elapsed since mid-night on the fractional part.
SQL Server is not the exception to this, thus the conversion to Float makes a lot of sense. Day 0 is Jan 01 1900 00:00:00 (AFAIK, in no particular time-zone, so you shall consider it "local time").
So, you can try this:
declare #ADate DateTime;
set #ADate = '19000101 00:00:00';
select CONVERT(float, #ADate); --should print 0
set #ADate = '19000101 12:00:00';
select CONVERT(float, #ADate); --should print 0.5
set #ADate = '19001231 06:00:00';
select CONVERT(float, #ADate); --should print 364.25
So, for your results, 40183 days has been passed since 01/01/1900 00:00:00 and 01/07/2010 00:00:00
Clarification: Unix like systems use a different approach to store datetimes: Seconds since Unix epoch (Jan 1 1970 00:00:00 UTC), which is more known as epoch time.
[Edit]
Date format on this response was changed to YYYYMMDD format on 20140416, after some new years of experience with SQL Server (and as #Damien said in his comment) this is the only safe format.
DateTime values are actually stored as two four-byte integers under the hood. The first four-byte integer represents the number of days since 1900-01-01. The second four-byte integer stores the number of milliseconds since midnight. When you convert a datetime into a float, the decimal portion represents the percentage of the 24-day that has past. Thus, 0.5 represents noon.
It's basically converting the datetime to an OLE Date. There's a decent description of the process in the documentation for System.DateTime.ToOADate():
http://msdn.microsoft.com/en-us/library/system.datetime.tooadate.aspx
The quick explanation is that the integer part is the number of days since 12/30/1899. The fractional part (zero in this case) is the time divided by 24.
This should help you understand the TSQL implementation (or implement your own):
DECLARE
#date DATETIME = '20180125 09:15:30.549',
#date_dec DECIMAL (26,10) = 43123.3857702546
SELECT
CAST(#date_dec AS DATETIME) AS [TSQL cast to DATETIME],
CAST(#date AS DECIMAL (26,10)) AS [TSQL cast to DECIMAL]
SELECT
DATEADD(DAY, FLOOR(#date_dec),
DATEADD(HOUR, FLOOR(#date_dec % 1 * 24),
DATEADD(MINUTE, FLOOR((#date_dec % 1 * 24) % 1 * 60),
DATEADD(SECOND, FLOOR(((#date_dec % 1 * 24) % 1 * 60) % 1 * 60),
DATEADD(MILLISECOND, FLOOR((((#date_dec % 1 * 24) % 1 * 60) % 1 * 60) % 1 * 1000), '19000101')
)
)
)
) AS [Manual cast to DATETIME],
DATEDIFF(DAY, '19000101', #date)
+ (
DATEPART(HOUR, #date)
+ (
DATEPART(MINUTE, #date)
+ (
DATEPART(SECOND, #date)
+ DATEPART(MILLISECOND, #date) / CAST(1000 AS FLOAT)
) / CAST(60 AS FLOAT)
) / CAST(60 AS FLOAT)
) / CAST(24 AS DECIMAL (26,10)) AS [Manual cast to DECIMAL]
Note that the result is not always the same as TSQL loses precision on last millisecond digit.

Convert bigint to datetime

I want to convert a value from bigint to datetime.
For example, I'm reading the HISTORY table of teamcity server. On the field build_start_time_server, I have this value on one record 1283174502729.
How can I convert it to a datetime value?
Does this work for you? It returns 30-8-2010 13:21:42 at the moment on SQL Server 2005:
select dateadd(s, convert(bigint, 1283174502729) / 1000, convert(datetime, '1-1-1970 00:00:00'))
I've divided by 1000 because the dateadd function won't work with a number that large. So you do lose a little precision, but it is much simpler to use.
Slightly different approach:
Your scenario:
SELECT dateadd(ms, 1283174502729 / 86400000, (1283174502729 / 86400000) + 25567)
FROM yourtable
Generic code:
SELECT dateadd(ms, yourfield / 86400000, (yourfield / 86400000) + 25567)
FROM yourtable
Output:
August, 30 2010 00:00:14
SQL Fiddle: http://sqlfiddle.com/#!3/c9eb5a/2/0
CAST(SWITCHOFFSET(CAST(dateadd(s, convert(bigint, [t_stamp]) / 1000, convert(datetime, '1-1-1970 00:00:00')) AS DATETIMEOFFSET), DATENAME (TZoffset, SYSDATETIMEOFFSET())) AS DATETIME)
The following takes new SQL terminology into account and will return the milliseconds (can also be modified for use in a calculated field.) [SQL Server 2012 or later]
declare #StartDate datetime2(3) = '1970-01-01 00:00:00.000'
, #milliseconds bigint = 1283174502729
, #MillisecondsPerDay int = 60 * 60 * 24 * 1000 -- = 86400000
SELECT DATEADD(MILLISECOND, TRY_CAST(#milliseconds % #millisecondsPerDay AS
INT), DATEADD(DAY, TRY_CAST(#milliseconds / #millisecondsPerDay AS INT),
#StartDate));
select Cast(Cast(19980324 as nvarchar) as Datetime)
If you want precision in milliseconds to be maintained then you could do as follows. Works on SQL server 2016
SELECT dateadd(ms, ((CONVERT(bigint, build_start_time_server)%1000)),
dateadd(ss, ((CONVERT(bigint, build_start_time_server)/1000)%60),
dateadd(mi, ((CONVERT(bigint, build_start_time_server)/1000)/60), '1970-01-01'))) FROM yourtable
The answer I got was
Monday, August 30, 2010 1:21 PM
To convert bigint to datetime/unixtime, you must divide these values by 1000000 (10e6) before casting to a timestamp.
SELECT
CAST( bigIntTime_column / 1000000 AS timestamp) example_date
FROM example_table
Simple and easy solution which won't require any added library or function to be imported
DATEADD(second,YourValue, CAST('1970-01-01 00:00:00' AS datetime))
Did you try FROM_UNIXTIME?
select from_unixtime('your_field') from 'your_table'
https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_from-unixtime
Works for me.