I currently have a challenge of storing a DateTime value in a NVarChar field so that it's culture independent.
I've read that you can convert the value to an int by using CONVERT(int, GETDATE(), 112) which should make it culture independent but the former statement doesn't store the time.
What is the industry standard of storing a DateTime as culture independent?
EDIT
Please note that I can't use DateTime in my scenario. It must be NVarChar.
EDIT 2
Alright, found the answer to my own question.
To convert a DateTime to it's binary(8) raw format:
convert(binary(8), GETDATE())
I then store the value in a VARCHAR field as follows:
CONVERT(VARCHAR(MAX), convert(binary(8), GETDATE()), 2)
To retrieve it back from the varchar field and convert it to DateTime:
CONVERT(DateTime,CONVERT(binary(8), [TextField], 2))
As var as I'm concerned, this will store a DateTime as culture independent.
EDIT 3
It seems like user Kaf has the best solution. I will rather use format 126 to convert it to text and then back to DateTime from text.
Thanks everyone and sorry for the confusion.
If you CANNOT store date as Datetime, you can use style 126 which gives ISO8601 format (yyyy-mm-ddThh:mi:ss.mmm (no spaces)). I think it is culture independent.
Fiddle demo
select convert(nvarchar(50),getdate(),126)
Best thing is to store Date as a DateTime/Date type.
You should use DATETIME or DATETIME2 data type to store date and time values. They are stored in binary format in the database and are culture independent.
You can read more on MSDN here: http://msdn.microsoft.com/en-us/library/ms187819(v=sql.100).aspx
More on how SQL Server stores the datetime values: "It uses 8 bytes to store a datetime value—the first 4 for the date and the second 4 for the time." (from: http://sqlmag.com/sql-server/solving-datetime-mystery)
I do not get this idea to store a date in a varchar field so that it is 'culture independant'. dateTime data type is culture independant. What is culture dependent is the way date values are displayed:
MM/dd/YYYY
dd/MM/YYYY
YYYY-MM-DD
etc
But, if the display changes, the underlying value itself is still the same ... and this is why you can easily 'convert' dates from one format to another....
So, for the sake of simplicity, I do strongly advise you to switch to a culture-independant, datetime field. Otherwise any further use of this field's content (calculation, display, print out, etc) will be a real PITA ...
Related
I can't make out from the documentation why SQL Server parses a text in a format other than the specified style.
Regardless of whether I provide text in the expected format:
SELECT CONVERT(DATETIME, N'20150601', 112)
or incorrect format (for style 113):
SELECT CONVERT(DATETIME, N'20150601', 113)
The results are the same: 2015-06-01 00:00:00.000 I would expect the latter to fail to convert the date (correctly).
What rules does it employ when trying to convert a VARCHAR to DATETIME? I.e. why does the latter (incorrect format style) still correctly parse the date?
EDIT: It seems I've not been clear enough. Style 113 should expect dd mon yyyy hh:mi:ss:mmm(24h) but it happily converts values in the format yyyymmdd for some reason.
Because the date is in a canonical format ie(20150101). The database engine falls over it implicitly. This is a compatibility feature.
If you swapped these around to UK or US date formats, you would receive conversion errors, because they cannot be implicitly converted.
EDIT: You could actually tell it to convert it to a pig, and it would still implicitly convert it to date time:
select convert(datetime,'20150425',99999999)
select convert(datetime,'20150425',100)
select convert(datetime,'20150425',113)
select convert(datetime,'20150425',010)
select convert(datetime,'20150425',8008135)
select convert(datetime,'20150425',000)
And proof of concept that this is a compatibility feature:
select convert(datetime2,'20150425',99999999)
Although you can still implicitly convert datetime2 objects, but the style must be in the scope of the conversion chart.
Reason why is the date N'20150601' converted to valid datetime is because of fact that literal N'20150601' is universal notation of datetime in SQL Server. That means, if you state datetime value in format N'yyyymmdd', SQL Server know that it is universal datetime format and know how to read it, in which order.
You should convert to varchar type in order to apply those formats:
SELECT CONVERT(varchar(100), CAST('20150601' as date), 113)
OK, you are converting datetime to datetime. What did you expect? In order to apply formats you should convert to varchar and you have to have date or time type as second parameter.
I was having problem in retrieving from SQL Server so I posted this [question][1]
I did not get any suitable answers. So I have changed the column datatype from datetime to varchar and now it works fine.
SELECT *
FROM test
WHERE (timeStamp BETWEEN '05-09-2013 18:23:57' AND '05-09-2013 18:23:59')
But my query if varchar datatype can play the role of datetime and in varchar we can also store the string then why sql provides datetime datatype? I know varchar occupies more space than datetime. I would like to know other reasons.
Change datatype of your column to datetime. You can do your query IF you'll use datetime instead of varchar in where clause:
select *
from test
where timeStamp between convert(datetime, '2013-09-05 18:23:57', 120) and convert(datetime, '2013-09-05 18:23:59', 120)
I'm pretty sure it would work even with implicit cast if you use ISO format of date:
select *
from test
where timeStamp between '2013-09-05 18:23:57' and '2013-09-05 18:23:59'
Here's more info about cast and convert.
Another reason apart from space is this:
Datetime has other functions like picking up the day, year, month,hours,minutes,seconds etc so that you don't have to write it for yourself. If you use varchar then it will be your responsibility to provide functions for future use. You should use split function to retrive the part of date you want.
Another is that a query on a varchar works slower when compared to Datetime when you use to conditions to compare month / day/ year
Always use proper DATETIME datatype to store date and time values. Refer this for more information
http://beyondrelational.com/modules/2/blogs/70/posts/10902/understanding-datetime-column-part-iv.aspx
I made a date according to the datetime format. But, I stored this in my DB as a string/nvarchar and not a datetime. Will I be able to compare such dates ? Is this a bad practice ?
I am using nvarchar to store a datetime as of now.
Yes you can still be able to compare them but this is certainly a bad practice because you will need to convert this strings into dates data type to be able to compare between them. If you have indexes define on the column, they will not be used anymore since the column will be converted and it will cuase slow performance on large database.
An example on comparing dates is like this:
SELECT *
FROM tableName
WHERE CONVERT(DATETIME, dateSTRColumn, XXX) > GETDATE()
where XXX is the current format of the date stored as string.
You will have to use either cast or convert to parse a datetime from the strings or compare the raw strings directly. The latter is possible depending on what format the strings are stored as. For example, if dates were stored in the format 'YYYYMMDD' you could simply compare string1 < string2.
I am seeeing my dates are stored in database in this format for a column (datetime datatype) 2011-01-14 10:15:41.787 i.e YYYY-MM-DD way . How could I make the default storage in YYYY-DD-MM format . Do I need to set that for all the DBS, or I can set it for single DB and how ?
I have the column in datetime datatype, right now it is saving as
2011-01-14 10:15:41.787 , my question is how can I set the db to store it as
2011-14-01 10:15:41.787
That is the crux of the confusion. Just because SQL Server Management Studio displays a datetime column in that format does not mean that it is stored AS TEXT YYYY-MM-DD hh:mm:ss.zzz. It is stored as binary, something like 0000101000001010..
Your dates are stored in SQL Server as a series of bytes (bits really) that make up some numeric value that is an offset from 1900-01-01. There is no inherent format the the dates. What you are referring to is that SSMS by default shows [display] datetime columns as YYYY-MM-DD hh:mm:ss.zzz. If you use a front-end programming tool, that too may impose a default [display] format unless you have asked for another one.
There is absolutely NO way to make SSMS show datetime data in another format through options or configuration. If you must, you would have to update the SQL query to convert the datetime column to a VARCHAR column containing the TEXTual equivalent in a particular format. That may be useful in SSMS, but would be bad when used as a data source to front-end GUI/web apps - since the values are not datetime and cannot be used for interval calculation, graphing, bound to date controls etc.
See this example of displaying time (getdate()) as YYYY-DD-MM, a very unusual format. Notice the date field/variable has to be used twice:
select stuff(convert(char(7), getdate(), 120), 5, 0, '-' + convert(char(2), getdate(), 3))
DATETIMEs are stored internally as two 4 byte integers, so firstly you are seeing a formatted representation for the UI - it's not actually stored in a particular date/time format as such.
e.g. if you insert just a date like "2010-01-01" then it will still hold the time element: 2010-01-01 00:00:00.000
If you're only interested in the DATE part, then you can format the DATETIME for output either in your front-end code or via your query:
e.g.
SELECT CONVERT(VARCHAR(8), GETDATE(), 121)
So even if the DATEs you insert contain a time, that will be ignored when returned. You could also ensure you only insert dates without the time specified - you need to handle that in whatever code is doing the INSERTs. e.g. from .NET, instead of passing in DateTime.Now you could pass in DateTime.Now.Date.
In SQL Server 2008, there is a DATE datatype which is there to only store a DATE (without time) which is really what you want in this kind of scenario.
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