converting datetime to float in sql - sql

converting datetime to float in sql
Hello, I have a question, how do I convert the difference of the following dates, for example: (2023-01-02 18:00:00)-(2023-01-01 17:00:00) into a decimal number?
I know how the conversion to an integer happens(cast(cast(test as date) - cast(testtwo as date) as int), but here I am confused.

You man look at DATEDIFF function. It allows you to:
returns the count (as a signed integer value) of the specified
datepart boundaries crossed between the specified startdate and
enddate.
Then, convert the seconds to a day:
SELECT DATEDIFF(SECOND, '2023-01-01 17:00:00', '2023-01-02 18:00:00') * 1.0 / (60*60*24) -- 1.041666666666

The DATETIME datatype is incredibly useful and flexible for things like this, although the rounded 3.3 millisecond resolution causes some folks pain.
If you want "Decimal Days" where the fractional part to the right of the decimal point represents time as a partial day, then the following will do the trick.
--===== Setup test values for clarity and ease of testing.
-- These variables could be changed out for columns in a table.
DECLARE #StartDT DATETIME = '2023-01-01 17:00:00'
,#EndDT DATETIME = '2023-01-02 18:00:00'
;
--===== Calulate the difference (duration) in decimal days.
SELECT DecimalDays = CONVERT(FLOAT,#EndDT-#StartDT)
;

Related

datediff() of 2 timestamps that contain decimal values

I've been stumbling with this issue for a couple days now, and cannot seem to figure out why, when my getdate() insert into the columns are providing a millisecond decimal to the military time format, I still cannot seem to be able to pull a decimal format datediff() result. Does it have to do with the engine not recognizing the decimal due to the surrounding '' characters?
When I use:
select datediff(s,'2013-06-01 21:59:59.141','2013-06-01 23:59:59.997')
It returns:
7200
And when I use:
select cast(datediff(s,'2013-06-01 21:59:59.141','2013-06-01 23:59:59.997') as float);
It returns:
7200
I am at a loss as to what I am missing in order to result in a decimal value.
Thanks
If you are trying to get the milliseconds of the difference, and you want to convert the units to seconds, you can try using something like the following:
SELECT DATEDIFF(MS,'2013-06-01 21:59:59.141','2013-06-01 23:59:59.997') / 1000.0
That'll produce: 7200.856000.
Please note that DATEDIFF(MS, ...) requires guarding for long time spans or it will give an overflow:
SELECT datediff(MS, '2013-06-30 23:59:59.997', '2013-06-01 21:59:59.141')
-- FAILURE: The datediff function resulted in an overflow. The number of dateparts separating two date/time instances is too large
You can use following method which is overflow-safe and gives you a float result:
SELECT cast(cast('2013-06-01 23:59:59.997' as datetime)-cast('2013-06-01 21:59:59.141' as datetime) as float) * 24.0
-- Returned 2.00023796296296
SELECT cast(cast('2013-06-30 23:59:59.997' as datetime)-cast('2013-06-01 21:59:59.141' as datetime) as float) * 24.0
-- Returned 698.000237962963
I'm not sure how this method works when time zone changed during the measured date period.

Converting string with microseconds to DATE

I get a string as input from an application that is supposed to be a date. For some asinine reason the developers of the application decided provide precision to the microsecond. Well, actually, to the tenth of a microsecond.
The string is in the format: 2014-08-15T17:38:22.2930000
Before they changed this input format I was using the following to convert the date.
select DATEADD(dd, 30, #Date)
I know I could just do a substring on the input and lop off the last 4 characters, however, I'm wondering if there is some way that I can use CONVERT to just convert the date, or if SQL just doesn't support dates with this type of precision.
Either of these should work:
SELECT CONVERT(DATE, '2014-08-15T17:38:22.2930000', 101)
SELECT CONVERT(DATETIME2, '2014-08-15T17:38:22.2930000', 101)
Whoops, the following assumes that a date and time are desired. Substituting in DATE for DATETIME2 will work, just as it does with CONVERT and the time component is simply dropped.
A CAST to DATETIME2 works (this is for SQL Server 2008 R2 - YMMV elsewhere),
select CAST('2014-08-15T17:38:22.2930001' AS DATETIME2) t;
as DATETIME2 has a maximum precision of 100ns, or 7 digits after the decimal.
Then it can be converted to a normal DATETIME (either explicitly or implicitly), although this loses precision,
select CAST(CAST('2014-08-15T17:38:22.2930001' AS DATETIME2) AS DATETIME) t;
However such lost of precision is not allowed directly in a CHAR -> DATETIME cast, and there are precision tolerances for the other casts.
select CAST('2014-08-15T17:38:22.293' AS DATETIME) t; -- OK*
select CAST('2014-08-15T17:38:22.2930' AS DATETIME) t; -- fail
-- although a cast to DATETIME2 is happy to lose some precision
select CAST('2014-08-15T17:38:22.2930001' AS DATETIME2) t; -- OK, no loss
select CAST('2014-08-15T17:38:22.29300014' AS DATETIME2) t; -- OK, loss
select CAST('2014-08-15T17:38:22.293000144' AS DATETIME2) t; -- OK, loss
select CAST('2014-08-15T17:38:22.2930001444' AS DATETIME2) t; -- fail
-- and a cast to DATE works up to 8 digits after the decimal
select CAST('2014-08-15T17:38:22.29300014' AS DATE) t; -- OK, date only
select CAST('2014-08-15T17:38:22.293000144' AS DATE) t; -- fail
*DATETIME has a precision of 3 decimal digits, but it does not have millisecond accuracy.
As far as I am aware, the same rules for CHAR -> DATETIME/DATETIME2 apply to COVERT and losing maximum precision still results in an error.
The ISO 8601 standard provides no limit to precision, but "the number of decimal places needs to be agreed to by the communicating parties".
SELECT CAST('2014-08-15T17:38:22.2930000' AS DATETIME2)
RESULT: 2014-08-15 17:38:22.2930000
Now since it is a valid datetime value in sql server, you have access to all the datetime functions, like you have mentioned in your question you wanted to use DATEADD()
Datetime2 gives you more precision than simple datetime data type, Read more about DATETIME2 data type here.

SQL: Using DATEADD with bigints

I have some SQL to convert javascript dates to SQL dates which works great. However, I've encoutered some data which is too large and is causing an exception:
Arithmetic overflow error converting expression to data type int
Here is the SQL in question:
DATEADD(MILLISECOND, cast(569337307200000 as bigint) % 1000, DATEADD(SECOND, cast(569337307200000 as bigint) / 1000, '19700101'))
I am running this on SQL Server 2008.
Just do the problematic DATEADD in two steps, starting with a coarser time unit (seconds, minutes, hours etc.), then dropping back to the fine grained one for the remainder.
Avoid going to the level of weeks and months though as that would require actual calendar calculations and we would prefer the system to handle that.
Example below needs to calculate a start time given a (possibly) large current duration in milliseconds.
-- large durations can overflow the integer argument needed for DATEADD
-- so do as two steps subtracting minutes (60000ms) and then remaining milliseconds.
DATEADD(ms, -large_duration_ms%60000, DATEADD(minute, -large_duration_ms/60000, GETDATE()))
One way I got around the Integer overflow issue was to subtract a more recent date from the microtime unix time stamp.
DATEADD(s, (CreationTimeStamp/1000-1384128000), '2013-11-11') AS CreateDate,
This will not fix the OP's problem because they will still overflow the max on the date column.
According to MSDN, in DATEADD (datepart , number , date )
number is an expression that can be resolved to an int that is added
to a datepart of date. User-defined variables are valid. If you
specify a value with a decimal fraction, the fraction is truncated and
not rounded.
Also notice that even if you give number as an integer, depending on your date & datepart, it could overflow the max range of the date which is 31-12-9999 for sql server 2008
Number has to be an integer. Here is a Test Demo
I had the same problem and I wanted to be meet the datetime range of mssql
Minimun datetime: 1753-01-01 00:00:00.000 (-6847804800)
Maximum datetime: 9999-12-31 23:59:59.997 (253402300799)
To achieve this the only solution I found was to loop to use DATEADD with int range values.
So based on this answer: https://stackoverflow.com/a/2904294/687490
CREATE FUNCTION dbo.fn_ConvertToBigDateTime (#Datetime BIGINT)
RETURNS DATETIME
AS
BEGIN
DECLARE #result datetime = Convert(datetime, '01/01/1970');
DECLARE #LocalTimeOffset BIGINT
,#AdjustedLocalDatetime BIGINT
,#MinIntValue INT
,#MaxIntValue INT
,#RemainingSeconds BIGINT;
-- define int limit
SET #MinIntValue = -2147483648;
SET #MaxIntValue = 2147483647;
-- compute the datetime with the offset
SET #LocalTimeOffset = DATEDIFF(second,GETDATE(),GETUTCDATE())
SET #AdjustedLocalDatetime = #Datetime - #LocalTimeOffset
-- going to the future
WHILE(#AdjustedLocalDatetime>#MaxIntValue)
BEGIN
SET #AdjustedLocalDatetime = #AdjustedLocalDatetime - #MaxIntValue;
SELECT #result = Convert(datetime, dateadd(ss, #MaxIntValue,#result));
END
-- going back in the past
WHILE(#AdjustedLocalDatetime<#MinIntValue)
BEGIN
SET #AdjustedLocalDatetime = #AdjustedLocalDatetime - #MinIntValue;
SELECT #result = Convert(datetime, dateadd(ss, #MinIntValue,#result));
END
RETURN (SELECT DATEADD(second,#AdjustedLocalDatetime, #result))
END;
You can then test the function with :
select dbo.fn_ConvertToBigDateTime(-6847804800) as 'min datetime',
dbo.fn_ConvertToBigDateTime(253402300799) as 'max datetime'
Hope it will help.
You can try converting the millis to days, add the days to beginning of EPOCH, and add the ms part to the date at the end. The problem is that you were trying to convert millis to seconds, which can still be too large number for INT for larger dates.
DATEADD(MILLISECOND,
CAST(myLongDateMs AS BIGINT) % 86400000,
DATEADD(day,
CAST(myLongDateMs AS BIGINT) / 86400000,
'19700101'
)
)
I faced this problem too. In my sql statement, the error occurred when the date time value is null.
My solution is to check whether the date time value is null using "CASE When". Only running the arithmetic when it is not null, and the problem solved.

convert Excel Date Serial Number to Regular Date

I got a column called DateOfBirth in my csv file with Excel Date Serial Number Date
Example:
36464
37104
35412
When i formatted cells in excel these are converted as
36464 => 1/11/1999
37104 => 1/08/2001
35412 => 13/12/1996
I need to do this transformation in SSIS or in SQL. How can this be achieved?
In SQL:
select dateadd(d,36464,'1899-12-30')
-- or thanks to rcdmk
select CAST(36464 - 2 as SmallDateTime)
In SSIS, see here
http://msdn.microsoft.com/en-us/library/ms141719.aspx
The marked answer is not working fine, please change the date to "1899-12-30" instead of "1899-12-31".
select dateadd(d,36464,'1899-12-30')
You can cast it to a SQL SMALLDATETIME:
CAST(36464 - 2 as SMALLDATETIME)
MS SQL Server counts its dates from 01/01/1900 and Excel from 12/30/1899 = 2 days less.
tldr:
select cast(#Input - 2e as datetime)
Explanation:
Excel stores datetimes as a floating point number that represents elapsed time since the beginning of the 20th century, and SQL Server can readily cast between floats and datetimes in the same manner. The difference between Excel and SQL server's conversion of this number to datetimes is 2 days (as of 1900-03-01, that is). Using a literal of 2e for this difference informs SQL Server to implicitly convert other datatypes to floats for very input-friendly and simple queries:
select
cast('43861.875433912' - 2e as datetime) as ExcelToSql, -- even varchar works!
cast(cast('2020-01-31 21:00:37.490' as datetime) + 2e as float) as SqlToExcel
-- Results:
-- ExcelToSql SqlToExcel
-- 2020-01-31 21:00:37.490 43861.875433912
this actually worked for me
dateadd(mi,CONVERT(numeric(17,5),41869.166666666664)*1440,'1899-12-30')
(minus 1 more day in the date)
referring to the negative commented post
SSIS Solution
The DT_DATE data type is implemented using an 8-byte floating-point number. Days are represented by whole number increments, starting with 30 December 1899, and midnight as time zero. Hour values are expressed as the absolute value of the fractional part of the number. However, a floating point value cannot represent all real values; therefore, there are limits on the range of dates that can be presented in DT_DATE. Read more
From the description above you can see that you can convert these values implicitly when mapping them to a DT_DATE Column after converting it to a 8-byte floating-point number DT_R8.
Use a derived column transformation to convert this column to 8-byte floating-point number:
(DT_R8)[dateColumn]
Then map it to a DT_DATE column
Or cast it twice:
(DT_DATE)(DT_R8)[dateColumn]
You can check my full answer here:
Is there a better way to parse [Integer].[Integer] style dates in SSIS?
Found this topic helpful so much so created a quick SQL UDF for it.
CREATE FUNCTION dbo.ConvertExcelSerialDateToSQL
(
#serial INT
)
RETURNS DATETIME
AS
BEGIN
DECLARE #dt AS DATETIME
SELECT #dt =
CASE
WHEN #serial is not null THEN CAST(#serial - 2 AS DATETIME)
ELSE NULL
END
RETURN #dt
END
GO
I had to take this to the next level because my Excel dates also had times, so I had values like this:
42039.46406 --> 02/04/2015 11:08 AM
42002.37709 --> 12/29/2014 09:03 AM
42032.61869 --> 01/28/2015 02:50 PM
(also, to complicate it a little more, my numeric value with decimal was saved as an NVARCHAR)
The SQL I used to make this conversion is:
SELECT DATEADD(SECOND, (
CONVERT(FLOAT, t.ColumnName) -
FLOOR(CONVERT(FLOAT, t.ColumnName))
) * 86400,
DATEADD(DAY, CONVERT(FLOAT, t.ColumnName), '1899-12-30')
)
In postgresql, you can use the following syntax:
SELECT ((DATE('1899-12-30') + INTERVAL '1 day' * FLOOR(38242.7711805556)) + (INTERVAL '1 sec' * (38242.7711805556 - FLOOR(38242.7711805556)) * 3600 * 24)) as date
In this case, 38242.7711805556 represents 2004-09-12 18:30:30 in excel format
In addition of #Nick.McDermaid answer I would like to post this solution, which convert not only the day but also the hours, minutes and seconds:
SELECT DATEADD(s, (42948.123 - FLOOR(42948.123))*3600*24, dateadd(d, FLOOR(42948.123),'1899-12-30'))
For example
42948.123 to 2017-08-01 02:57:07.000
42818.7166666667 to 2017-03-24 17:12:00.000
You can do this if you just need to display the date in a view:
CAST will be faster than CONVERT if you have a large amount of data, also remember to subtract (2) from the excel date:
CAST(CAST(CAST([Column_With_Date]-2 AS INT)AS smalldatetime) AS DATE)
If you need to update the column to show a date you can either update through a join (self join if necessary) or simply try the following:
You may not need to cast the excel date as INT but since the table I was working with was a varchar I had to do that manipulation first. I also did not want the "time" element so I needed to remove that element with the final cast as "date."
UPDATE [Table_with_Date]
SET [Column_With_Excel_Date] = CAST(CAST(CAST([Column_With_Excel_Date]-2 AS INT)AS smalldatetime) AS DATE)
If you are unsure of what you would like to do with this test and re-test! Make a copy of your table if you need. You can always create a view!
Google BigQuery solution
Standard SQL
Select Date, DATETIME_ADD(DATETIME(xy, xm, xd, 0, 0, 0), INTERVAL xonlyseconds SECOND) xaxsa
from (
Select Date, EXTRACT(YEAR FROM xonlydate) xy, EXTRACT(MONTH FROM xonlydate) xm, EXTRACT(DAY FROM xonlydate) xd, xonlyseconds
From (
Select Date
, DATE_ADD(DATE '1899-12-30', INTERVAL cast(FLOOR(cast(Date as FLOAT64)) as INT64) DAY ) xonlydate
, cast(FLOOR( ( cast(Date as FLOAT64) - cast(FLOOR( cast(Date as FLOAT64)) as INT64) ) * 86400 ) as INT64) xonlyseconds
FROM (Select '43168.682974537034' Date) -- 09.03.2018 16:23:28
) xx1
)
For those looking how to do this in excel (outside of formatting to a date field) you can do this by using the Text function https://exceljet.net/excel-functions/excel-text-function
i.e.
A1 = 132134
=Text(A1,"MM-DD-YYYY") will result in a date
This worked for me because sometimes the field was a numeric to get the time portion.
Command:
dateadd(mi,CONVERT(numeric(17,5),41869.166666666664)*1440,'1899-12-31')

tsql getdate conversion

I know that when i do the following, it converts getdate to int
select cast (getdate() as int)
Getdate output on my server is "2010-06-11 14:42:20.100" and the int to which the above command is converting to is 40339. What is this integer? Did this int consider minutes and
seconds? i am confused. Please help.
Regards
Manjot
This number is the number of days since the reference date, which is 01/01/1900. You should get the same result from:
SELECT DATEDIFF(day, 0, GETDATE())
Internally, SQL stores datetimes as two 4-byte integers. The first integer (which you are getting in your statement) represents the number of days since the reference date. The second integer represents the number of 1/300 second intervals since midnight. You can find the second integer by converting first to binary, then to int:
SELECT CONVERT(int, CONVERT(binary(4), GETDATE()))