Varchar to Datetime in TSQL - sql

How can I convert date and time value stored like
20200406151341
to DATETIME value 2020/04/06 15:31:41 (YYYY/MM/DD HH:MM:SS.000)? I am unable to find suitable CONVERT() format and the only way so far is to parse the VARCHAR like below.
select dateadd(second, cast(substring('20200406151341',13,2) as int),dateadd(minute, cast(substring('20200406151341',11,2) as int), dateadd(hour,cast(substring('20200406151341',9,2) as int),convert(datetime, left('20200406151341',8), 112)))).
It works yet it's hard to read and understand especially when I have to use it within SELECT statement multiple times.
Also I am surprised query with above conversions is as fast the one with dates stored directly in DATETIME format. Does MSSQL server uses some kind of cache so it does have to do the conversion only once per row?
I use MSSQL Server 2016.

I don't think there is a built in, simple way to do this.
You don't have to go to seconds to do this. You can easily convert the first 8 characters to a date. With some string manipulation, you can convert the last six to a time -- and then add time (as datetime values):
select convert(datetime, left(dt, 8)) + convert(datetime, stuff(stuff(right(dt, 6), 5, 0, ':'), 3, 0, ':'))
from (values ('20200406151341')) v(dt);
You can also use arithmetic rather than 3 dateadd()s:
select dateadd(second,
right(dt, 2) + 60*substring(dt, 11, 2) + 60*60*substring(dt, 9, 2),
convert(datetime, left(dt, 8)))
from (values ('20200406151341')) v(dt)
Note: This uses implicit conversion from a string to an integer (as does your version).

You can use stuff() :
select convert(datetime,
stuff(stuff(stuff(stuff(col, 9, 0, ' '), 10, 0, ''), 12, 0, ':'), 15, 0, ':'
)

Let's throw in a couple more options to the mix:
DECLARE #StrDate varchar(14) = '20200406151341'
SELECT DATETIMEFROMPARTS(
LEFT(#StrDate, 4), -- year
SUBSTRING(#StrDate, 5, 2), -- month
SUBSTRING(#StrDate, 7, 2), -- day
SUBSTRING(#StrDate, 9, 2), -- hour
SUBSTRING(#StrDate, 11, 2), -- minute
SUBSTRING(#StrDate, 13, 2), -- second
0 -- millisecond
) As [Using DateTimeFromParst],
CONVERT(DateTime, LEFT(#StrDate, 8), 112) + -- Date
CONVERT(DateTime, STUFF(STUFF(RIGHT(#StrDate, 6), 5, 0, ':'), 3, 0, ':'), 114) -- Time
As [Using convert and stuff]
Results:
Using DateTimeFromParst Using convert and stuff
2020-04-06 15:13:41 2020-04-06 15:13:41

I suggest using try_convert() or try_cast() in case your strings are invalid, and if invalid they will return NULL instead of raising an error. Refer to the links for further detail on these functions.
declare #val varchar(20)
set #val = '20200416151341'
select try_convert(datetime,
stuff(stuff(stuff(stuff(#val, 9, 0, ' '), 10, 0, ''), 12, 0, ':'), 15, 0, ':')
);
select try_cast(
stuff(stuff(stuff(stuff(#val, 9, 0, ' '), 10, 0, ''), 12, 0, ':'), 15, 0, ':')
as datetime);

Related

SQL server - converting string to datetime

I need to convert a column that contains dates and times in the format 08-JAN-19 09.35.58.173000000 AM to datetime. I've included the code I've tried below - the code commented out is currently not working.
SELECT [last_updated_at]
, SUBSTRING([last_updated_at], 1, 9)
, convert(datetime, SUBSTRING([last_updated_at], 1, 9), 103) as Date
, SUBSTRING([last_updated_at], 11, 18)
--, convert(datetime, SUBSTRING([last_updated_at], 11, 18), 103) as Time --This fails
--, convert(datetime, SUBSTRING([last_updated_at], 1, 9), 103) + convert(datetime, SUBSTRING([last_updated_at], 11, 18), 103) as DateTime --final output datetime column
FROM #temp_dates
The only problem with your data is that you need the time portion of your date to look like this: 2019-01-08 09:35:58.173 instead of 2019-01-08 09.35.58.173 (the dots after the hour and minute need to be colons instead of dots.
--==== Original formatting
DECLARE #date VARCHAR(20) = '08-JAN-19 09.35.58.173000000'
--==== Solution
SELECT CAST(STUFF(STUFF(#date,13,1,':'),16,1,':') AS DATETIME);
Note that this truncates (not rounds) to the nearest millisecond so, 09:35:58.173 becomes 09:35:58.100. If milliseconds are an issue then a bit more finagling will be required.
Please try the below:
select convert(datetime, substring(replace(replace('08-JAN-19 09.35.58.173000000', '-', ' '), '.', ':'), 1, 18))
Before you can convert a string to datetime, your string must conform to certain patterns as shown in https://learn.microsoft.com/en-us/sql/t-sql/data-types/datetime-transact-sql?view=sql-server-ver15

How do I covert a number to a date in SQL?

I have a field named SECURED that has dates listed as 123120, 040320 which is actually 12/31/20 or 4/03/20.
I was able to convert the date in the SELECT area with:
SELECT LEFT(SECURED, 2) + '/' + replace(replace(SECURED, LEFT(SECURED, 2), ''),
RIGHT(SECURED, 2), '') + '/' + RIGHT(SECURED, 2) as 'Modified SECURED as Date'
WHERE CONVERT(date, SECURED, 101)
BETWEEN CONVERT(date, getdate() - 30, 101)
AND CONVERT(date, getdate(), 101)
How can I pull in information from the SECURED column with a date of 30 days ago?
It doesn't work and still sees a date as a number.
You can use datefromparts() to convert your string to a date:
datefromparts(
concat('20', substring(secured, 5, 2)),
substring(secured, 1, 2),
substring(secured, 3, 2)
)
Then you can check it against a given interval:
datefromparts(
concat('20', substring(secured, 5, 2)),
substring(secured, 1, 2),
substring(secured, 3, 2)
) between dateadd(day -30, cast(getdate() as date)) and cast(getdate() as date)
If secured is a string, you can do a little manipulation and a simple cast():
select convert(date, concat('20', right(secured, 2), left(secured, 4))
You might find it convenient to actually create a computed column so this is always available:
alter table t add secured_date as (try_convert(date, concat('20', right(secured, 2), left(secured, 4))
You can even persist the column and create an index, so your queries are more efficient.
There're many ways to convert a 6 digits INT to DATE:
You can do a convertion using LTRIM and CAST like this:
SELECT CAST(RIGHT(LTRIM(123120),2) + LEFT(LTRIM(123120),4) AS DATE)
Using LTRIM with SUBSTRING:
SELECT CAST(SUBSTRING(LTRIM(040320), 5, 2) + SUBSTRING(LTRIM(040320), 1, 4) AS DATE)
Using CONVERT:
SELECT CAST((RIGHT(CONVERT(VARCHAR(6), 123120),2) +
LEFT(CONVERT(VARCHAR(6), 123120),4)) AS DATE)
Or using CONVERT with SUBSTRING:
SELECT CAST(SUBSTRING(CONVERT(VARCHAR(6), 040320), 5, 2) +
SUBSTRING(CONVERT(VARCHAR(6), 040320), 1, 4) AS DATE)
Using STR:
SELECT CAST(RIGHT(STR(123120, 6) ,2) + LEFT(STR(123120, 6) ,4) AS DATE)
Or using STR with SUBSTRING:
SELECT CAST(SUBSTRING(STR(040320, 6), 5, 2) + SUBSTRING(STR(040320, 6), 1, 4) AS DATE)
This casting will format the date as expected but your dates need be
in format mmddyy
Standard EUA (style 10) DATE format (mm-dd-yy) without century (yy)
Edit after comments:
What's the table name of this query?
What's the SECURED field datatype? INT? VARCHAR?
You need convert a date and compare between last 30 days and today?
The query below resolve your problem? (change TABLE_NAME to your table name)
SELECT LEFT(SECURED, 2) + '/' + replace(replace(SECURED, LEFT(SECURED, 2), ''),
RIGHT(SECURED, 2), '') + '/' + RIGHT(SECURED, 2) as 'Modified SECURED as Date'
FROM TABLE_NAME
WHERE CAST(RIGHT(LTRIM(SECURED), 2) + LEFT(LTRIM(SECURED), 4) AS DATE)
BETWEEN GETDATE() - 30 AND GETDATE()

Find error in jobsteps of all jobs that ran over night [duplicate]

I want write a query to get the last 24 hours worth of job record from the "msdb.dbo.sysjobhistory" table, but I can't get because I get the "run_date" and "run_time" columns are returned as a number. How can I convert the "run_date" and "run_time" columns into a datetime variable, and use this to get the last 24 hour job history?
Check out this post - it shows how to "decode" those run_date columns from sysjobhistory.
You should be able to get the entries from the last 24 hours with a query something like this:
SELECT
j.name as JobName,
LastRunDateTime =
CONVERT(DATETIME, CONVERT(CHAR(8), run_date, 112) + ' '
+ STUFF(STUFF(RIGHT('000000' + CONVERT(VARCHAR(8), run_time), 6), 5, 0, ':'), 3, 0, ':'), 121)
FROM
msdb..sysjobs j
INNER JOIN
msdb..sysjobhistory jh ON j.job_id = jh.job_id
WHERE
CONVERT(DATETIME, CONVERT(CHAR(8), run_date, 112) + ' '
+ STUFF(STUFF(RIGHT('000000' + CONVERT(VARCHAR(8), run_time), 6), 5, 0, ':'), 3, 0, ':'), 121) > DATEADD(HOUR, -24, GETDATE())
For databases after 2000, there is a function in the msdb database you can call that will return datetime:
msdb.dbo.agent_datetime(run_date, run_time) as 'RunDateTime'
If you are using sql 2000, you can copy the source of that function from a later version and create it in your instance of 2000. I wish I could take credit for all of this, but I originally found it here: mssqltips.com
A co-worker of mine pointed out that the other given solutions only find jobs that we're started 24 hours ago (or less), not jobs that were completed 24 hours ago (or less). He proposed something along the lines of the following to location completed jobs:
SELECT j.name AS JobName
,LastCompletedDateTime = DATEADD(day, (run_duration / 240000), CONVERT(DATETIME, msdb.dbo.agent_datetime(run_date, run_time))) +
STUFF(STUFF(REPLACE(STR((run_duration % 240000), 7, 0), ' ', '0'), 4, 0, ':'), 7, 0, ':')
FROM msdb..sysjobs j
INNER JOIN msdb..sysjobhistory jh ON j.job_id = jh.job_id
WHERE DATEADD(day, (run_duration / 240000), CONVERT(DATETIME, msdb.dbo.agent_datetime(run_date, run_time))) +
STUFF(STUFF(REPLACE(STR((run_duration % 240000), 7, 0), ' ', '0'), 4, 0, ':'), 7, 0, ':') > DATEADD(HOUR, - 24, GETDATE())
I believe part of this comes from a blog, but we cannot locate it, when I do I'll link that as well...

How to convert String to Datetime including time part in SQL [duplicate]

This question already has answers here:
How to convert datetime string without delimiters in SQL Server as datetime?
(6 answers)
Closed 6 years ago.
I want to convert below string to DateTime in SQL.
20140601152943767
I know convert(date,'20140601152943767') this but I want time part also.
Above function only returns me Date part.
Thanks in advance.
I would use following solution:
SELECT CONVERT(DATETIME, STUFF(STUFF(STUFF(STUFF('20140601152943767', 9, 0, ' '), 12, 0, ':') , 15, 0, ':'), 18, 0, '.'))
Note #0: All those STUFF calls will convert source strings from 20140601152943767 to 20140601 15:29:43.767.
Note #1: SELECT STUFF('abcef', 4, 1, 'DDD') will replace substring starting from index 4 with a length of 1 char (e) with DDD -> abcDDDf
Note #2: SELECT STUFF('abcef', 4, 0, 'DDD') returns abcDDDef
You can try lik ethis:
select
concat(convert(date,LEFT('20140601152943767',8)), ' ' , Convert(time,Dateadd(SECOND,
Right('20140601152943767',2)/1,
Dateadd(MINUTE,
Right('20140601152943767',4)/100,
Dateadd(hour,
Right('20140601152943767',6)/10000,
'1900-01-01')))) )
as myDate
Output:
2014-06-01 22:38:07.0000000
Well, first of all - you need conversion not to date but to datetime type.
Second - you should always specify format as mentioned:
https://msdn.microsoft.com/en-us/library/ms187928(v=sql.120).aspx
e.g.
select convert(datetime, '20140501', 112)
3 - there is no such format supported for your value demonstrated, so you have to modify your value yo something like yyyy-mm-ddThh:mi:ss.mmm (iso) or to make custom conversion with substring and so on.
;WITH myvalues AS (
SELECT '20140601152943767' value
)
SELECT
convert(date, LEFT(mv.value, 8), 112),
cast(STUFF(STUFF(STUFF(STUFF(mv.[value], 1, 8, ''), 7, 0, '.'), 5, 0, ':'), 3, 0, ':') AS TIME)
FROM myvalues mv
Try This one
declare #datetime varchar(20) = '20140601152943767'
select convert(varchar(20),convert(date,LEFT(#datetime,8))) + ' ' + substring(RIGHT(#datetime,9), 1, 2)
+ ':' + substring(RIGHT(#datetime,9), 3, 2)
+ ':' + substring(RIGHT(#datetime,9), 5, 2)
+ '.' + substring(RIGHT(#datetime,9), 7, 3)
I know some might argue that this is not the best way , but still it's an alternative.Few people have already used convert and stuff functions .
Try this out.Easy to understand.Also test your subqueries.
select y1||'-'||M1||'-'||d1||' '||h1||':'||mi||':'||s1||':'||f1 as xdate
from
(
select substr('20140601152943767',1,4) Y1 from dual
),
(
select substr('20140601152943767',5,2)M1 from dual
),
(
select substr('20140601152943767',7,2) d1 from dual
),
(
select substr('20140601152943767',9,2) h1 from dual
),
(
select substr('20140601152943767',11,2) mi from dual
),
(
select substr('20140601152943767',13,2) s1 from dual
),
(
select substr('20140601152943767',15,3) f1 from dual
)
Output:
2014-06-01 15:29:43.767

SQL Server : format 700 as time

I've run an import which has updated many records in my tblRota.StartTime and tblRota.EndTime in the format 900 and 1700.
How can I reformat these to 09:00 and 17:00?
The datatypes of both columns is varchar.
Thank you.
You could use this query:
select stuff(right('0' + replace([StartTime], ':', ''), 4), 3, 0, ':'),
stuff(right('0' + replace([EndTime], ':', ''), 4), 3, 0, ':')
from [tblRota]
The steps are:
Remove the :: replace([StartTime], ':', '')
Get the time on 4 digits: right('0' + <3Or4DigitTime>, 4)
Insert the :: stuff(<4DigitTime>, 3, 0, ':')
Use some string manipulation:
UPDATE tblRota
SET StartTime = LEFT(RIGHT('0'+StartTime , 4),2)+':'+RIGHT(StartTime ,2),
EndTime = LEFT(RIGHT('0'+EndTime , 4),2)+':'+RIGHT(EndTime ,2)