Have researched a lot, both on this site, and others, but still don't have a valid solution. I have a column of varchar datatype, it contains DateTime data. I need to store only the Date portion in a Date type column. Tried different ways of Cast, Convert, and other functions, but still haven't been able to make it work.
Basically I want to convert this
Tue Apr 26 2016 13:54:53 GMT+0200 (CEST)
to
04/26/2016
Assuming your Day and Month part is always 3 characters long this can be done simply as this:
DECLARE #d VARCHAR(100)='Tue Apr 26 2016 13:54:53 GMT+0200 (CEST)';
SELECT CONVERT(DATE,SUBSTRING(#d,4,12),109);
If this was to easy one would have to find the blank(s) with CHARINDEX, but I don't think so...
The format code 109 means mon dd yyyy hh:mi:ss:mmmAM (or PM) Details here.
And be aware that formats containing language depending parts are directly sent by the devil to create never ending pain... This will not work on a server with a different language setting!
Declare #String varchar(max) = 'Tue Apr 26 2016 13:54:53 GMT+0200 (CEST)'
Select cast(Substring(#String,12,4)+Substring(#String,4,7) as date)
Returns
2016-04-26
Okay a few things here you have a field that looks to be psuedo ISO 8601 but is not the standard. The first question will be: "Where does this come from?" Typically you don't have the 'Tue' or 'GMT' or '(CEST)' in a standard and the offset from Greenwich Meantime is in the format (+/-)##:## NOT (+/-)####. SQL and many other formats can easily accept a standardized string in the ISO 8601 format. Good brief here: https://www.w3.org/TR/NOTE-datetime
That being said you can easily get what you want with a little know how:
DECLARE
#S VARCHAR(128) = 'Tue Apr 26 2016 13:54:53 GMT+0200 (CEST)'
, #Valid VARCHAR(128)
--Legitimate ISO 8601 string:
SELECT #Valid = RTRIM(LTRIM(REPLACE(STUFF(STUFF(#S, 1, 4, ''), LEN(#S)-12, 12, ':00'), 'GMT', '')))
SELECT #Valid
--Legitimate DateTimeOffset
SELECT CAST(#Valid AS DATETIMEOFFSET)
--Now that I have a legimiate DateTimeOffset I can downconvert easily
SELECT CAST(CAST(#Valid AS DATETIMEOFFSET) AS DATE)
--AND... Now that I have a legimate Date I can format it many different ways
SELECT CONVERT(VARCHAR, CAST(CAST(#Valid AS DATETIMEOFFSET) AS DATE), 101)
The real thing to realize here is there is magical conversion of DateTime using the convert function. But you may be wondering 'what if I want it to look different?'. Try this page:
http://www.sql-server-helper.com/tips/date-formats.aspx
I would be leery though of just finding the placement of were things appear to be coming from a string even though I can parse your example. If you are getting things not following a standard you should know why. The main reason being you may be able to get this to work for a specific instance but not be able to repeat this pattern over and over.
Related
I have nvarchar values with the following format
10:27:32.357 +03 Aug 31 2022
How to convert those to DatetimeOffset variables in T-SQL?
I have to deal with huge amounts of data, so I want to avoid rebuild the value as segments and then use DATETIMEOFFSETFROMPARTS.
Based on the one example we have, and assuming your dates are always in the format hh:mm:ss.nnn [+-]tzoffset MMM dd yyyy (which is honestly an awful format) you could do something like this:
DECLARE #BadDateString nvarchar(50) = N'10:27:32.357 +03 Aug 31 2022';
SELECT CONVERT(datetimeoffset(3),CONVERT(varchar(10),CONVERT(date,RIGHT(#BadDateString,11)),120)+'T'+REPLACE(LEFT(#BadDateString,16),' ','') + ':00')
I strongly suggest, however, that you fix the problem by having the application that is sending this data in this format as a strongly typed date and time (datetimeoffset) value in the first place; T-SQL's forté isn't strong at string manipulations like like.
I wrote a SQL query to have the results from 2016 Apr 01 to 2016 May 01.
When I wrote:
where a.DateIntervention >= '2016-04-01'
and a.DateIntervention < '2016-05-01'
I obtain the results from 2016 Jan 04 00:00:00.000, so it is reading my dates as ydm, although the results show the date format as ymd (2016-01-04 00:00:00.000)
And when I ask the system about the date format it tells me it is dmy (!)
How to change this setting so that I can write my queries like ymd and continue obtaining the results like ymd?
In SQL Server, you don't need to. If you drop the hyphens then the strings will be interpreted using YYYYMMDD:
where a.DateIntervention >= '20160401' and a.DateIntervention < '20160501'
I prefer the hyphens because they are more readable, accepted in most databases, and generally work in SQL Server. There are particular settings where they don't work, but 'YYYYMMDD' is always interpreted as a date.
I should add, you can throw in a cast()/convert() if you like:
where a.DateIntervention >= cast('20160401' as date) and
a.DateIntervention < cast('20160501' as date)
There's no built-in way for the query to realize "I was supplied a YMD date, I should output dates as YMD too.".
In theory you could call SET DATEFORMAT ymd, but I mislike that because it might affect something farther down the line you don't know about.
If you want an explicit formatting/parsing style during conversion (which is almost always a good idea), you need to explicitly convert it, and supply the style:
-- 126 is hyphenated, but has extra parts if something other than date is used
CONVERT(DATE, '2017-07-28', 126)
Of course, the best option is to supply the parameter as an actual DATE type, and get output the same way, which saves you from converting back and forth to a string type, and avoids the formatting problem. This may not be available in a cases, however (like ad hoc queries).
How can one convert the string "01 December 2016" to a date type in SQL Server?
CONVERT(date, '01 December 2016', 106)
Expected date outcome "01 Dec 2016"
If 2012+ you can use Format()
Select Format(convert(date,'01 December 2016'),'dd MMM yyyy')
Returns
01 Dec 2016
It is very dangerous to work with culture specific date/time formats and it is even worse to work with language and culture specific formats...
If ever possible store date/time values in appropriate types!
In my (german) system a direct cast or convert would break due to "December", which is "Dezember" in Germany. Have a look at this:
SET LANGUAGE English; --try the same with "German"
DECLARE #d VARCHAR(100)='01 December 2016';
SELECT CONVERT(VARCHAR(11),CONVERT(DATE,#d,106),106);
The result
01 Dec 2016
One should never rely on implicit conversions: Call CONVERT with the third parameter in any case!
The third parameter 106 tells SQL Server the date's format (how to parse it). The first CONVERTSs target type is DATE. This - now properly represented! - date can be converted again to VARCHAR(11) with 106 as third parameter now specifying the output format.
For deeper insight in language specific date parts you can run this query:
SELECT * FROM sys.syslanguages;
btw: If you are using SQL Server 2012+ you should call FORMAT() as pointed out by John Cappelletti
I have a varchar(200) column called Submit_Date and I am trying to convert it to MM/DD/YYYY format. When I do that I get the following error:
Msg 242, Level 16, State 3, Line 1The conversion of a varchar data type to a datetime data type resulted in an out-of-range value.
Sample Data of the table is:
Submit_Date
-----------------------
27-09-2013 16:15:00 CST
30-09-2013 16:30:24 CST
27-09-2013 10:03:46 CST
I tried the following:
Select Convert(datetime,Submit_date,101) from dbo.Tickets
You've committed about 15 cardinal sins about date/time here. First, the quick answer:
DECLARE #x VARCHAR(200);
SELECT #x = '27-09-2013 16:15:00 CST'
SELECT CONVERT(CHAR(10),CONVERT(DATETIME,LEFT(#x,10),105),101);
Next:
Why on earth are you storing date/time data in a varchar(200) column? You are aware that anyone can insert values like '09-27-2013' or '465-32-207floob' in there, right? If you need time zone information you can look at the DATETIMEOFFSET data type (but note that it is not DST-aware).
Why are you storing a regional format like dd-mm-yyyy? If the first value were 07-11-2013 I'd have to guess if you meant July 11 or November 7. If you're not going to do it right and use a proper date/time data type, why use a string format that makes people guess? You are much better off with a format that is unambiguous, such as yyyy-mm-ddThh:mm:ssZ.
Similarly, why are you outputting a different regional format like mm/dd/yyyy? If you output '05/06/2013' are you 100% confident that everyone in your audience will know you meant May 6 and not June 5? Your output should be unambiguous as well. If you absolutely must format in some regional and ambiguous format, use the string formatting capabilities of your client. For example, C# has .ToString() and .Format() which are much more powerful and efficient in presenting dates with string formats that T-SQL will ever be.
try the following SQL query to achieve the expected result:
SELECT convert(varchar, convert(date, '27-09-2013 16:15:00', 105), 101)
I have been given a specification that requires the ISO 8601 date format, does any one know the conversion codes or a way of getting these 2 examples:
ISO 8601 Extended Date 2000-01-14T13:42Z
ISO 8601 Basic Date 20090123T105321Z
When dealing with dates in SQL Server, the ISO-8601 format is probably the best way to go, since it just works regardless of your language and culture settings.
In order to INSERT data into a SQL Server table, you don't need any conversion codes or anything at all - just specify your dates as literal strings
INSERT INTO MyTable(DateColumn) VALUES('20090430 12:34:56.790')
and you're done.
If you need to convert a date column to ISO-8601 format on SELECT, you can use conversion code 126 or 127 (with timezone information) to achieve the ISO format.
SELECT CONVERT(VARCHAR(33), DateColumn, 126) FROM MyTable
should give you:
2009-04-30T12:34:56.790
This
SELECT CONVERT(NVARCHAR(30), GETDATE(), 126)
will produce this
2009-05-01T14:18:12.430
And some more detail on this can be found at MSDN.
If you just need to output the date in ISO8601 format including the trailing Z and you are on at least SQL Server 2012, then you may use FORMAT:
SELECT FORMAT(GetUtcDate(),'yyyy-MM-ddTHH:mm:ssZ')
This will give you something like:
2016-02-18T21:34:14Z
Just as #Pxtl points out in a comment FORMAT may have performance implications, a cost that has to be considered compared to any flexibility it brings.
Gosh, NO!!! You're asking for a world of hurt if you store formatted dates in SQL Server. Always store your dates and times and one of the SQL Server "date/time" datatypes (DATETIME, DATE, TIME, DATETIME2, whatever). Let the front end code resolve the method of display and only store formatted dates when you're building a staging table to build a file from. If you absolutely must display ISO date/time formats from SQL Server, only do it at display time. I can't emphasize enough... do NOT store formatted dates/times in SQL Server.
{Edit}. The reasons for this are many but the most obvious are that, even with a nice ISO format (which is sortable), all future date calculations and searches (search for all rows in a given month, for example) will require at least an implicit conversion (which takes extra time) and if the stored formatted date isn't the format that you currently need, you'll need to first convert it to a date and then to the format you want.
The same holds true for front end code. If you store a formatted date (which is text), it requires the same gyrations to display the local date format defined either by windows or the app.
My recommendation is to always store the date/time as a DATETIME or other temporal datatype and only format the date at display time.
You technically have two options when speaking of ISO dates.
In general, if you're filtering specifically on Date values alone OR looking to persist date in a neutral fashion. Microsoft recommends using the language neutral format of ymd or y-m-d. Which are both valid ISO formats.
Note that the form '2007-02-12' is considered language-neutral only
for the data types DATE, DATETIME2, and DATETIMEOFFSET.
Because of this, your safest bet is to persist/filter based on the always netural ymd format.
The code:
select convert(char(10), getdate(), 126) -- ISO YYYY-MM-DD
select convert(char(8), getdate(), 112) -- ISO YYYYMMDD (safest)
For ISO 8601 format for Datetime & Datetime2, below is the recommendation from SQL Server. It does not support basic ISO 8601 format for datetime(yyyyMMddThhmmss).
DateTime
YYYY-MM-DDThh:mm:ss[.mmm]
YYYYMMDD[ hh:mm:ss[.mmm]]
Examples:
2004-05-23T14:25:10
2004-05-23T14:25:10.487
Datetime2
YYYY-MM-DDThh:mm:ss[.nnnnnnn]
YYYY-MM-DDThh:mm:ss[.nnnnnnn]
Examples:
2004-05-23T14:25:10
2004-05-23T14:25:10.8849926
You can convert them using 126 option
--Datetime
DECLARE #table Table(ExtendedDate DATETIME, BasicDate Datetime)
DECLARE #ExtendedDate VARCHAR(30) = '2020-07-01T08:39:17' , #BasicDate VARCHAR(30) = '2009-01-23T10:53:21.000'
INSERT INTO #table(ExtendedDate, BasicDate)
SELECT convert(datetime,#ExtendedDate,126) ,convert(datetime,#BasicDate,126)
SELECT * FROM #table
go
-- Datetime2
DECLARE #table Table(ExtendedDate DATETIME2, BasicDate Datetime2)
DECLARE #ExtendedDate VARCHAR(30) = '2000-01-14T13:42:00.0000000' , #BasicDate VARCHAR(30) = '2009-01-23T10:53:21.0000000'
INSERT INTO #table(ExtendedDate, BasicDate)
SELECT convert(datetime2,#ExtendedDate,126) ,convert(datetime2,#BasicDate,126)
SELECT * FROM #table
go
Datetime
+-------------------------+-------------------------+
| ExtendedDate | BasicDate |
+-------------------------+-------------------------+
| 2020-07-01 08:39:17.000 | 2009-01-23 10:53:21.000 |
+-------------------------+-------------------------+
Datetime2
+-----------------------------+-----------------------------+
| ExtendedDate | BasicDate |
+-----------------------------+-----------------------------+
| 2000-01-14 13:42:00.0000000 | 2009-01-23 10:53:21.0000000 |
+-----------------------------+-----------------------------+
this is very old question, but since I came here while searching worth putting my answer.
SELECT DATEPART(ISO_WEEK,'2020-11-13') AS ISO_8601_WeekNr