I feel like I've read a ton of these corresponding posts such as,
converting Epoch timestamp to sql server(human readable format)
& How do I convert a SQL server timestamp to an epoch timestamp?
But can't seem to get my particular use-case working. I need to convert an epoch timestamp to a normal date/time value. Currently, the column is a nvarchar(max) type. Here's an example of one of the dates:
1478563200000
I'm trying to get it to look like the following:
2019-01-14 00:00:00.0000000
I've tried the following to no success all with the same error message:
select DATEADD(SS, CONVERT(BIGINT, baddate), '19700101') as gooddate
from table
"Arithmatic overflow error converting expression to data type int"
I've tried minutes, seconds, days, all same error message and at this point I'm about to tell the guys to send the data in a different format.
Try
select DATEADD(SS, CONVERT(INT, CONVERT(BIGINT, baddate)/1000), '19700101') as gooddate
from table
DATEADD expects an int, not a bigint. Since your timestamp is in milliseconds, it won't "fit" in an int. If you trade-in millisecond resolution for second resolution by dividing by 1000 it will fit in an integer and make DATEADD happy. So first we convert the NVARCHAR to BIGINT (why store as NVARCHAR in the first place?), then divide by 1000 and then convert to INT.
Another option is to divide the value by 1000 at the time of insert (and, again, make the column an int in the first place). That'll save a lot of CONVERTs everywhere (you can get rid of them all) and probably speed up your queries quite nicely. Then again, you could even convert the column to datetime (or datetime2 or whatever type is best suited) and leave out the entire dateadd/convert mess in your queries alltogether. Always try to get your data ad close to the final datatype you need it in later.
Edit: I just realized you can probably leave one convert out:
select DATEADD(SS, CONVERT(BIGINT, baddate)/1000, '19700101') as gooddate
from table
This is the same as the original suggestion, only this time the cast to int is implicit. But converting your data upon insert is still probably the better idea. So the rest of my post still stands.
You can get the correct result to the millisecond, that works with years 0001 through 9999, using the accepted answer
here.
declare #x nvarchar(max) = N'1478563200000'
select dbo.UnixTimeToDateTime2(#x)
Related
My problem is that we are using Datetime column in our database but we need to show our date in different calendar like Hijri or Shamsi With the Time.
So with complex query cost of conversion is very high and i need an efficient way to get Time and concatenate it with the converted date part.
Right now i am using these approaches
1-
CONCAT(dbo.getShamsiDate( JI.Job_start_execution_date ),' ',FORMAT(JI.Job_start_execution_date,'HH:mm:s')) AS [JobStart]
JobStart
1399/05/13 19:25:47
2-
SELECT CONVERT(VARCHAR(10), #Job_start_execution_date , 108) JobStart;
JobStart
----------
14:43:35
My question is this:
Which one is faster or be suited and is there any faster way?
Just cast/convert it to a time, as that retain the correct typing (it's still a date and time data type):
SELECT CONVERT(time(0),datetimevalue), CAST(datetimevalue AS time(3))
As the value is a datetime, the value will be accurate to 1/300th of a second, however, choose a precision appropriate for your data.
In SQL Server, I am getting the error:
Error -2147217913: Conversion failed when converting date an/or time from character string.
Error in converting
I am sure that my fields are in date field, but why this error keeps on showing?
First I validated first if the data type is really a date column:
CASE
WHEN ISDATE(dbo.AdditionalDetailInfo.UserDefined2) = 1
THEN dbo.AdditionalDetailInfo.UserDefined2
ELSE NULL
END AS ReceivedDate
I found out that yes, it's correct. so i proceed with converting this field where UserDefined2 value should always be plus 1 day.
CONVERT(VARCHAR(12), DATEADD(DAY, 1, CONVERT(DATETIME, dbo.AdditionalDetailInfo.UserDefined2)), 103) AS ReceivedDate
Please let me know if there's something wrong with my query as I really can't diagnose what went wrong.
See screenshot:
See this link, the actual data and in SQL server + 1 day
Maybe the field is indeed a date field, so it could be that no conversion is required. Try DATEADD(DAY, 1, dbo.AdditionalDetailInfo.UserDefined2).
If the column is indeed a string column, the you forgot to specify the style parameter when reading the value, you only used it when converting back. Try this instead:
CONVERT(VARCHAR(12), DATEADD(DAY, 1, CONVERT(DATETIME, dbo.AdditionalDetailInfo.UserDefined2, 103)), 103) AS ReceivedDate
MSDN says that date, time and datetime types are not allowed as arguments to ISDATE but in practical terms, passing a date to it:
SELECT ISDATE(getutcdate())
Causes the datetime to be converted to varchar implicitly, passed to ISDATE as varchar, which promptly then returns a 1
As such we've no guarantee that your column really is a date type like you say, so I'm guessing it's probably a string.
Really, what you should do is change your column to be a date type. Don't store dates as strings; if Microsoft had intended you to do this and thought for a second it was a good idea, they wouldn't have implemented other column types than char based ones
If you cannot convert your column to date then you'll need to find the bad value:
select * from table where isdate(column) =0
Note that your attempt to convert style 103 (dd/mm/yyyy) may be failing because you have data that isn't in this style eg Christmas as 12/25/2000
Isdate might not pick this up because your database date format is set to mm/dd/yyyy and isdate thinks it's ok. Change your database date format so that isdate can properly tell what is a good date and what is a bad date
https://learn.microsoft.com/en-us/sql/t-sql/functions/isdate-transact-sql?view=sql-server-2017
And then, please, for the love of doing this properly, use a date typed column, not a string typed one
We need more information. In particular, we need to know what data type the UserDefined2 is. If you tell us that, then we can give better replies.
Just a note that ISDATE is a pretty worthless function since it returns 1 if the string is convertible to datetime. But what if what you really have os datetime2? Or smalldatetime? Because of that, use TRY_CAST instead.
Also, you just gave us pieces of queries, expressions. We don't see the context. There is something called predicate pushing in SQL Server that can mess things up for you (SQL Server pushes a predicate deeper into the query resulting that an expression work over non-datetime values even though you think that you have excluded them in a WHERE clause.
Also, note that how a datetime value is interpreted when you have separators and use the old types (datetime or datetime2) depends on the login's language setting.
More info in http://karaszi.com/the-ultimate-guide-to-the-datetime-datatypes
I would like to keep my dates as datetime datatype by also be in MM/DD/YYYY format. I know how to do this by converting them to a varchar, but want to keep the datetime format. Can anyone help with this?
Currently I have tried
SELECT CONVERT(datetime, GETDATE(), 101)
which is not working...
There is a basic misunderstanding in your question. Repeat after me: Datetimes don't have a format.
It helps if you think of them as just an array of seven integers (year, month, day, hours, minutes, seconds, milliseconds) with certain constraints. That's not in any way accurate, but it helps to get the notion out of your head that something akin to 12/31/2015 is stored in your database.
Datetimes only get a format when (implicitly or explicitly) being converted to strings. You already know how to set the format when explicitly converting to string, now all that is left to do is to find the implicit conversion that is obviously bothering you and replace it with an explicit one.
Date and datetime Values stored in the database are NOT in any recognizable format. They are stored in binary (1s and 0s) in a proprietary format where one part represents the number of days since a defined reference date (1 jan 1900) in SQL server). and the other part represents the time portion of the value. (in sql server, its the number of 1/300ths of a second since midnight.)
ALL formatting of dates and date times, no matter what format you wish for, is done only after the values have been extracted from the database, before you see them on screen, in whatever application you are using.
You can find all the formats that the SQL Server convert function can use on this MSDN Convert Link
I am trying to insert a time only value, but get the following error
ex {"SqlDateTime overflow. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM."} System.Exception
From the front end, the time is selected using the "TimeEdit" control, with the up and down arrows. The table in SQL Server has the fields set as smalldatetime. I only need to store the time. I use the following to return data to the app
select id,CONVERT(CHAR(5),timeFrom,8)as timeFrom,CONVERT(CHAR(5),timeTo,8)as timeTo
FROM dbo.Availability
where id = #id
and dayName = #weekday
How do I pass time only to the table?
Edit ~ Solution
As per Euardo and Chris, my solution was to pass a datetime string instead of a time only string. I formatted my result as per Time Format using "g".
Thanks
You can set the date to 1/1/1753 wich is date min value for datetime in MSSQL and then add the hour you want to store. Of course you have to consider this every time you need to get the value, but you can wrap that with some helpers.
Or you can use MSSQL 2008 and use the new TIME datatype.
Pick a date that is in the range(ie, 1/1/1970) and use it for everything you insert.
If you are only keeping track of the time, think about storing it in an int as an offset from midnight in whatever granualarity you need (seconds, minutes, hours, ...). You can then convert it to a TimeSpan in your code using the appropriate TimeSpan.From??() method. To go back the other way, you can use TimeSpan.Total?? and truncate if need be. If you need to do manual queries you can write a SQL function that will convert hours/mins/seconds to the equivalent offset.
I prefer this over using a datetime and picking an arbitrary day as it makes the purpose of the field clearer, which reduces confusion.
there is no such thing as Time in SQL, there is only DateTime.
For your purpose, I would use something like this to only return the time portion.
SELECT (GETDATE() - (CAST(FLOOR(CAST(GETDATE() as FLOAT)) AS DateTime)))
where GETDATE() is the datetime you want to filter.
When setting the time in the database, you will have to add '01/01/1901' or '01/01/1753' to the time.
Dont use CAST and Convert to varchar when working with datetime, its slow. Stick to floating numerical operations.
I have a large table with 1 million+ records. Unfortunately, the person who created the table decided to put dates in a varchar(50) field.
I need to do a simple date comparison -
datediff(dd, convert(datetime, lastUpdate, 100), getDate()) < 31
But it fails on the convert():
Conversion failed when converting datetime from character string.
Apparently there is something in that field it doesn't like, and since there are so many records, I can't tell just by looking at it. How can I properly sanitize the entire date field so it does not fail on the convert()? Here is what I have now:
select count(*)
from MyTable
where
isdate(lastUpdate) > 0
and datediff(dd, convert(datetime, lastUpdate, 100), getDate()) < 31
#SQLMenace
I'm not concerned about performance in this case. This is going to be a one time query. Changing the table to a datetime field is not an option.
#Jon Limjap
I've tried adding the third argument, and it makes no difference.
#SQLMenace
The problem is most likely how the data is stored, there are only two safe formats; ISO YYYYMMDD; ISO 8601 yyyy-mm-dd Thh:mm:ss:mmm (no spaces)
Wouldn't the isdate() check take care of this?
I don't have a need for 100% accuracy. I just want to get most of the records that are from the last 30 days.
#SQLMenace
select isdate('20080131') -- returns 1
select isdate('01312008') -- returns 0
#Brian Schkerke
Place the CASE and ISDATE inside the CONVERT() function.
Thanks! That did it.
Place the CASE and ISDATE inside the CONVERT() function.
SELECT COUNT(*) FROM MyTable
WHERE
DATEDIFF(dd, CONVERT(DATETIME, CASE IsDate(lastUpdate)
WHEN 1 THEN lastUpdate
ELSE '12-30-1899'
END), GetDate()) < 31
Replace '12-30-1899' with the default date of your choice.
How about writing a cursor to loop through the contents, attempting the cast for each entry?When an error occurs, output the primary key or other identifying details for the problem record.
I can't think of a set-based way to do this.
Not totally setbased but if only 3 rows out of 1 million are bad it will save you a lot of time
select * into BadDates
from Yourtable
where isdate(lastUpdate) = 0
select * into GoodDates
from Yourtable
where isdate(lastUpdate) = 1
then just look at the BadDates table and fix that
The ISDATE() would take care of the rows which were not formatted properly if it were indeed being executed first. However, if you look at the execution plan you'll probably find that the DATEDIFF predicate is being applied first - thus the cause of your pain.
If you're using SQL Server Management Studio hit CTRL+L to view the estimated execution plan for a particular query.
Remember, SQL isn't a procedural language and short circuiting logic may work, but only if you're careful in how you apply it.
How about writing a cursor to loop through the contents, attempting the cast for each entry?
When an error occurs, output the primary key or other identifying details for the problem record.
I can't think of a set-based way to do this.
Edit - ah yes, I forgot about ISDATE(). Definitely a better approach than using a cursor. +1 to SQLMenace.
In your convert call, you need to specify a third style parameter, e.g., the format of the datetimes that are stored as varchar, as specified in this document: CAST and CONVERT (T-SQL)
Print out the records. Give the hardcopy to the idiot who decided to use a varchar(50) and ask them to find the problem record.
Next time they might just see the point of choosing an appropriate data type.
The problem is most likely how the data is stored, there are only two safe formats
ISO YYYYMMDD
ISO 8601 yyyy-mm-dd Thh:mm:ss:mmm(no spaces)
these will work no matter what your language is.
You might need to do a SET DATEFORMAT YMD (or whatever the data is stored as) to make it work
Wouldn't the isdate() check take care of this?
Run this to see what happens
select isdate('20080131')
select isdate('01312008')
I am sure that changing the table/column might not be an option due to any legacy system requirements, but have you thought about creating a view which has the date conversion logic built in, if you are using a more recent version of sql, then you can possibly even use an indexed view?
I would suggest cleaning up the mess and changing the column to a datetime because doing stuff like this
WHERE datediff(dd, convert(datetime, lastUpdate), getDate()) < 31
cannot use an index and it will be many times slower than if you had a datetime colum,n and did
where lastUpdate > getDate() -31
You also need to take into account hours and seconds of course