Trying to import a rather unusual formatted datetime sting in SQL.
The Source is an automated export from a Cisco networking-system, I can't alter it's formatting.
The format is Sun Dec 02 03:59:54 CET 2018
Tried datetimefromparts(), convert() combined with substring()'s
CREATE FUNCTION [dbo].[Cisco2dateTime]
( #CDate varchar(28)) RETURNS datetime
AS
BEGIN
RETURN ( datetimefromparts(
right(#CDate,4),
case substring(#CDate,5,3) when 'Jan' then '01' when 'Feb' then '02' when 'Mar' then '03' when 'Apr' then '04' when 'May' then '05' when 'Jun' then '06' when 'Jul' then '07' when 'Aug' then '08' when 'Sep' then '09' when 'Okt' then '10' when 'Nov' then '11' when 'Dec' then '12' END,
substring(#CDate,9,2),
substring(#CDate,12,2),
substring(#CDate,15,2),
substring(#CDate,18,2),0) )
END
GO
}
Any idea's how to do this more efficient?
If the incoming format is consistent, you can shrink it down to something like this:
DECLARE #time NVARCHAR(28) = 'Sun Dec 02 03:59:54 CET 2018'
SELECT CAST(SUBSTRING(#time,4,17) + RIGHT(#time,4) AS DATETIME)
Returns 2018-12-02 03:59:54.000
Edited for #Clockwork-Muse
If you want to include the timezone information, you can use a timezone table to match the abbreviations or, if you only have a handful of potential timezones, you can use a table value constructor like in the new example which will return a timezoneoffset:
DECLARE #time NVARCHAR(30) = 'Sun Dec 02 03:59:54 CET 2018'
SELECT TODATETIMEOFFSET(CAST(SUBSTRING(#time,4,17) + RIGHT(#time,4) AS DATETIME), z.TZOffset)
FROM
(
VALUES ('CET','+01:00'),('AST','+03:00'),('NZDT','+13:00')
)AS z(TZName, TZOffset)
WHERE #time LIKE '%'+z.TZName+'%'
Related
im learning sql (sqlite)...
question: how to elegantly convert one columns content into another column?
example:
i have a table eventid with a column orgdate that contain dates in a format that should be converted as indicated below
orgdate examples => resulting newdate format
"September 18, 2015" => "2015-09-18" -- existence of multiple spaces in orgdate
"September 5, 2015" => "2015-09-05" -- prepended 0 on day part of result
"september 5, 2015" => "2015-09-05" -- existence of different letter cases in input
in the code example below, columns orgdate and newdate are contained in eventtable and the newdate (nulls to start with) is modified by the procedure.
WITH tmpview(orgdate, eventid, cleandate) AS ( -- first create a "clean" date to work on in the subsequent UPDATE
SELECT orgdate, eventid,
replace( -- replace Nspaces=>1space "hack" via non printable char(17) char(18) sequence
replace(
replace(
replace( -- replace ',' with space
orgdate,
",", ' '),
" ", char(17)||char(18)),
char(18)||char(17),''),
char(17)||char(18),' ')
FROM eventtable)
UPDATE eventtable SET newdate =
(SELECT
substr(cleandate,length(cleandate)-3,4) || '-' || -- get year YYYY
CASE substr(upper(cleandate), 1, 3) -- get month MM
WHEN 'JAN' THEN '01'
WHEN 'FEB' THEN '02'
WHEN 'MAR' THEN '03'
WHEN 'APR' THEN '04'
WHEN 'MAY' THEN '05'
WHEN 'JUN' THEN '06'
WHEN 'JUL' THEN '07'
WHEN 'AUG' THEN '08'
WHEN 'SEP' THEN '09'
WHEN 'OCT' THEN '10'
WHEN 'NOV' THEN '11'
WHEN 'DEC' THEN '12'
ELSE "*ERROR*" || substr(upper(cleandate), 1, 3)
END || '-' ||
CASE length(replace(substr(cleandate, instr(cleandate," ")+1, 2)," ","")) -- get day DD
WHEN 1 THEN "0" -- prepend 0 if length is 1
WHEN 2 THEN ""
END ||
replace(substr(cleandate, instr(cleandate," ")+1, 2)," ","")
FROM tmpview
WHERE
tmpview.orgdate = eventtable.orgdate and tmpview.eventid = eventtable.eventid );
this code obviously is very long and naive, my questions:
how to achieve the same result much more succintly?
as a first modification, how to avoid repetitions in the code via aliases, eg. for the CASE expression replace(substr(cleandate, instr(cleandate," ")+1, 2) which is duplicated further on
how not to rely on the newdate column already existing, but creating it in the same procedure?
of course, i can envision getting a very much cleaner and intelligble procedure via several stages of temporary tables, but i wonder what is the idiomatic way of going about this.
thanks for any answers, i think seeing this by example, will greatly help me get a good head start on sql and maybe can serve others as an addition to the pool of examples out there (i have tried to find answers to the posed questions in other examples but have been unable to synthesise them into what i need)
There is no simple transformation of the format you have to YYYY-MM-DD.
You must use the string functions that SQLite supports:
UPDATE eventtable
SET newdate =
SUBSTR(orgdate, -4) || '-' ||
CASE UPPER(SUBSTR(TRIM(orgdate), 1, 3))
WHEN 'JAN' THEN '01'
WHEN 'FEB' THEN '02'
WHEN 'MAR' THEN '03'
WHEN 'APR' THEN '04'
WHEN 'MAY' THEN '05'
WHEN 'JUN' THEN '06'
WHEN 'JUL' THEN '07'
WHEN 'AUG' THEN '08'
WHEN 'SEP' THEN '09'
WHEN 'OCT' THEN '10'
WHEN 'NOV' THEN '11'
WHEN 'DEC' THEN '12'
END || '-' ||
REPLACE(SUBSTR(SUBSTR(orgdate, 1, INSTR(orgdate, ',') - 1), -2), ' ', '0')
This covers the cases that you mention in your question.
See the demo.
Results:
> | orgdate |
> | :--------- |
> | 2015-09-18 |
> | 2015-09-05 |
> | 2015-09-05 |
I have a period 201604 (nvarchar). Is there a way that I can convert 201604 to APR16?
Use the DATENAME & SUBSTRING functions, like this:
declare #str nvarchar(50) = '201604'
select UPPER(left(datename(mm,cast(#str+'01' as date)),3))+substring(#str,3,2) --APR16
It is a bit ugly, but you can't use any of the built-in date formatting stuff as is. Feel free to swap out the case statement for a join if you have a month names table, etc.:
DECLARE #exampleVal NVARCHAR(6) = '201604';
SELECT CASE SUBSTRING(#exampleVal, 5, 2)
WHEN '01' THEN 'JAN'
WHEN '02' THEN 'FEB'
WHEN '03' THEN 'MAR'
WHEN '04' THEN 'APR'
WHEN '05' THEN 'MAY'
WHEN '06' THEN 'JUN'
WHEN '07' THEN 'JUL'
WHEN '08' THEN 'AUG'
WHEN '09' THEN 'SEP'
WHEN '10' THEN 'OCT'
WHEN '11' THEN 'NOV'
WHEN '12' THEN 'DEC'
END +
SUBSTRING(#exampleVal, 3, 2)
Try this:
Add '01' (as first day of month), so convert your varchar to datetime and get the datename of the month:
declare #myperiod nvarchar(10)
SET #myperiod = '201604'
SET #myperiod = #myperiod + '01'
SELECT UPPER(SUBSTRING(DATENAME(month, CONVERT(datetime, #myperiod)), 1, 3)) +
SUBSTRING(CONVERT(varchar, DATEPART(year, CONVERT(datetime, #myperiod))), 3, 4)
Add 01 at the last, so that it changes to a valid date format. Then use the datename function:
DECLARE #STRING VARCHAR(10)='201604'
SELECT DATENAME(MONTH,#STRING+'01') +' '+SUBSTRING(#STRING,3,2)
Output:
April 16
In two lines:
declare #napis varchar(6)='201506'
SELECT UPPER(LEFT(DATENAME(month, #napis+'01'),3)) + SubString(#napis,3,2)
Another option is by using Format() and DateFromParts(). This will work in SQL Server 2012 or newer versions:
Declare #Period NVarchar (6) = N'201604'
Declare #Format NVarchar (5) = N'MMMyy'
Select Upper(Format(DateFromParts(Left(#Period, 4), Right(#Period, 2), 1), #Format))
APR16
Use simple this
declare #test nvarchar(max) = '201604'
select left(DATENAME(month, #test +'01'),3) + SubString(#napis,3,2)
Another way:
DECLARE #Date varchar(6) = '201604'
SELECT REPLACE(SUBSTRING(CONVERT(char(9), CAST(#Date +'01' as Date), 6), 4, 7), ' ', '')
Try this one..
DECLARE #DATE NVARCHAR(6) = '201604'
SELECT datename(MONTH,CONVERT(DATE,CONVERT(DATE,LEFT(#DATE,4)+'.'+RIGHT(#DATE,2)+'.01',102),102))
I have a column called "Mon-YY" (varchar(n) data type) in one of my tables which has values like:
Aug-12
Sep-12
Oct-12
Nov-12
Dec-12
Jan-13
Feb-13
Mar-13
Apr-13
May-13
Jun-13
I want to compare these values and retrieve the records from the table based on the date range specified.
I am assuming I'd need to convert the above values into DATE format. But I'm not sure then how do I keep track of days too.
You can use the DATEPART function, but you need to do it on a full date:
SELECT DATEPART(MM, 'Aug-12') --> error
SELECT DATEPART(MM', 01-Aug-12') --> 8
So try something like this:
SELECT
DATEPART(MM, CONCAT('01-', [Mon-YY])) AS TheMonth,
DATEPART(YYYY, CONCAT('01-', [Mon-YY])) AS TheYear
FROM myTable
ORDER BY TheYear, TheMonth
SELECT CONVERT (date, REPLACE (MyColumn, '-', ' 01 '))
FROM MyTable
Something like this should give you a date. It will always be the first of the month. You can use the expression in a WHERE clause with <, >, or BETWEEN. I don't know why you would need to keep track of them.
I used cast
-- example table and data
DECLARE #table table
(
[Mon-YY] varchar(20)
)
insert into #table values ('Aug-12')
insert into #table values ('Sep-12')
insert into #table values ('Oct-12')
insert into #table values ('Nov-12')
insert into #table values ('Dec-12')
insert into #table values ('Jan-13')
insert into #table values ('Feb-13')
insert into #table values ('Mar-13')
insert into #table values ('Apr-13')
insert into #table values ('May-13')
insert into #table values ('Jun-13')
select cast('01-' + [Mon-YY] as Date)
from #table
To convert these values to date you should use:
SELECT CONVERT(VARCHAR(20), '01 ' + [Mon-YY], 6) as BeginOfInterval
To get the last day of a month, you should use (look here):
SELECT DATEADD(s,-1,DATEADD(mm,
DATEDIFF(m,0,CONVERT(VARCHAR(20), '01 ' + [Mon-YY], 6))+1,0)) as EndOfInterval
Then you could use this two queries to get the first and last dates of interval.
A solution is to transform your column in something easier to sort like a number.
Bellow I transform the column in the full year followed by the month (numeric index 1 to 12) but this is used only in order by clause.
select *
from theTable
--where ???
order by case when right([mon-yy],2) <= 70 then '19' else '20' end +
right([mon-yy],2) +
case left([mon-yy],3)
when 'Jan' then '01'
when 'Feb' then '02'
when 'Mar' then '03'
when 'Apr' then '04'
when 'May' then '05'
when 'Jun' then '06'
when 'Jul' then '07'
when 'Aug' then '08'
when 'Sep' then '09'
when 'Oct' then '10'
when 'Nov' then '11'
when 'Dec' then '12'
end
USE [MAS_CAN]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[spHistorybyCalenderYear]--create a stored proc
#Year int = '2013'
AS
Begin
SET NOCOUNT ON
SELECT
isnull(round(l.UnitPrice*l.QuantityShipped,2),0) as SalesAmount,
isnull(round(l.unitCost*l.QuantityShipped,2),0) as CostAmount,
(case
when month(h.INVOICEDATE)=01 then '01'
when month(h.INVOICEDATE)=02 then '02'
when month(h.INVOICEDATE)=03 then '03'
when month(h.INVOICEDATE)=04 then '04'
when month(h.INVOICEDATE)=05 then '05'
when month(h.INVOICEDATE)=06 then '06'
when month(h.INVOICEDATE)=07 then '07'
when month(h.INVOICEDATE)=08 then '08'
when month(h.INVOICEDATE)=09 then '09'
when month(h.INVOICEDATE)=10 then '10'
when month(h.INVOICEDATE)=11 then '11'
when month(h.INVOICEDATE)=12 then '12'
END) as Period
FROM AR_INVOICEHISTORYHEADER h join AR_INVOICEHISTORYDETAIL l on (h.INVOICENO = l.INVOICENO)
Group by l.unitprice,l.unitcost,l.quantityShipped,h.invoicedate
order by Period
END
I would like to group it by period...Say I would like to see
Period SalesAmount CostAmount
01 22 19
02 24 25
Use this:
GROUP BY l.unitprice, l.unitcost, l.quantityShipped, CAST(MONTH(h.invoicedate) as varchar)
Also, you can get rid of that large case statement if you use this in its place:
SELECT
isnull(round(l.UnitPrice*l.QuantityShipped,2),0) as SalesAmount,
isnull(round(l.unitCost*l.QuantityShipped,2),0) as CostAmount,
CAST(MONTH(h.invoicedate) as varchar) as Period
FROM ...
As #Kaf mentioned, if you want Period to be 0 padded you can use either of these instead of the direct CAST:
right(100 + month(h.invoicedate),2)
left(convert(varchar, h.invoicedate, 10), 2)
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 11 years ago.
I am going nuts with datetime and SQL Server.
I have (example) Aug 4 2011 12:00AM
How do I convert this to a datetime (or smalldatetime) type.
convert(datetime, 'Aug 4 2011 12:00AM')
EDIT: it works
Thanks.
This does work for me on SQL Server 2008.
select convert(datetime, 'Aug 4 2011 12:00AM') as ConvertResult
ConvertResult
-------------
2011-08-04 00:00:00.000
What's happening is an implicit conversion, though, not always trustworthy. The format specifier for your date format is 100, found in the table on the CAST and CONVERT docs. Try this:
select convert(datetime, 'Aug 4 2011 12:00AM', 100) as ConvertResult
ConvertResult
-------------
2011-08-04 00:00:00.000
Have you tried this way ?
convert(datetime, 'Aug 4 2011 12:00AM', 120)
120 is for style formatting.
Check this link for full documentation
http://msdn.microsoft.com/en-us/library/ms187928.aspx
you can "massage" the data a bit: (Warning: not tested, but something along these lines should work). As a note, this is a brute force method if no other way works.
declare #datestring varchar(30);
set #datestring = 'Aug 4 2011 12:04AM';
select convert(datetime,
substring(#datestring, 8,4) + '-' +
case lower(left(#datestring, 3))
when 'jan' then '01'
when 'feb' then '02'
when 'mar' then '03'
when 'apr' then '04'
when 'may' then '05'
when 'jun' then '06'
when 'jul' then '07'
when 'aug' then '08'
when 'sep' then '09'
when 'oct' then '10'
when 'nov' then '11'
when 'dec' then '12'
end + '-' +
right('00' + ltrim(rtrim(substring(#datestring, 5, 2))), 2) + ' ' +
substring(#datestring, 13,50)
) as Converted;