SQL Server: Why are dates in ISO-8601 format language dependent? - sql

I need some help understanding date format handling in SQL Server.
If you try the following, it will return a correct result:
SET LANGUAGE English
SELECT CAST('2013-08-15' AS DATETIME)
-- 2013-08-15 00:00:00.000
This, however, will result in a conversion error because apparently SQL Server interprets '8' as the day and '15' as the month:
SET LANGUAGE German
SELECT CAST('2013-08-15' AS DATETIME)
-- Conversion failed when converting date and/or time from character string.
I know that I can use the language-independent (slightly adapted ISO-8601) format YYYYMMDD (without dashes), and it will work in any language.
I don't understand however why YYYY-MM-DD is language dependent, when SQL Books clearly says
"The interpretation depends on the combination of string literal format, ... and default language option settings. ... Some string literal formats are not affected by these settings. ... The ISO 8601 format does not depend on these settings and is an international standard."
http://technet.microsoft.com/en-us/library/ms180878%28v=sql.105%29.aspx
Even looking at the dateformat returned by select * from sys.syslanguages gives no indication - the date format is dmy, so it doesn't match the ISO-8601 format either.
So, the questions are:
Why is the ISO-8601 format language-dependent, even though Books Online says otherwise?
Where can I find the exact format SQL Server uses when parsing ISO-8601 dates?
UPDATE:
Reading further down on http://technet.microsoft.com/en-us/library/ms180878%28v=sql.105%29.aspx#ISO8601Format, it says 'To use the ISO 8601 format, you must specify each element in the format. This includes the T, the colons (:), the + or - , and the periods (.)' (e.g. 2004-05-23T14:25:10).
The table right above (http://technet.microsoft.com/en-us/library/ms180878%28v=sql.105%29.aspx#StringLiteralDateandTimeFormats) says that the ISO 8601 Numeric is not DATEFORMAT dependent, but it also is not Multilanguage. I'm not sure where to find additional information about the Multilanguage part though - e.g., the exact format used in each language.

This related question might help with languages and ISO-8601 date formats.
Why is SQL Server misinterpreting this ISO 8601 format date?
See the article The ultimate guide to the datetime datatypes which was also linked in the answer for more information on the datetime types used by SQL Server.

My guess would be to maintain backwards compatibility. The new datatypes in SQL Server 2008 datetime2 and date is not dependent on SET LANGUAGE or SET DATEFORMAT. Here is a connect item that suggests to change the behaviour for datetime as well.

Hard to answer a question starting with "Why" :-)
This may not answer your question, but for dates there is one string format which will work across ALL locales: 'YYYYMMDD'
Try:
SET LANGUAGE English
SELECT CAST('20130815' AS DATETIME)
SET LANGUAGE German
SELECT CAST('20130815' AS DATETIME)
SET LANGUAGE Japanese
SELECT CAST('20130815' AS DATETIME)
This will give the expected result.

Related

SQL Server doesn't get date format dd-mm-yyyy

I'm trying to INSERT date variable into my SQL server.
The input format I'm trying to insert is: dd-mm-yyyy
And my SQL server column (which defined as type DATE) expect mm-dd-yyyy.
My PC date format is dd-mm-yyyy.
The error msg:
Conversion failed when converting date and/or time from character string.
Questions:
Why is the expected format mm-dd-yyyy and not dd-mm-yyyy?
How can I make the INSERT command work with this or another date format?
Thanks.
The format that your PC uses for dates doesn't matter when passing literal string for dates, the language setting for the LOGIN you are using to connect to SQL Server does. As the value is being interpreted as MM-dd-yyyy this very likely means that your language setting is (American) ENGLISH.
If, therefore, you are the only person that uses that LOGIN you may well want to change the language of your LOGIN to be appropriate for yourself. Most of the European languages, including BRITISH English (because the British don't speak English Microsoft? 😒) use the format dd-MM-yyyy.
Really, however, what you should be doing is using an unambiguous date format, of which there are only 2 in SQL Server, regardless of the language setting and data type. Those 2 formats are yyyyMMdd and yyyy-MM-ddThh:mm:ss.nnnnnnn. If you are always using the newer date and time data types (so not datetime or smalldatetime), then yyyy-MM-dd( hh:mm:ss.nnnnnnn) is also unambiguous, however, as it's language specific for the older data type then I don't normally recommend it's use.
Storage wise, date and time data types don't have a format, so your column isn't "expected" a value in the format MM-dd-yyyy, as it doesn't retain the "format data" that the value was passed in. Again, the only reason why a value like 13-12-2020 is working is because your language setting, which uses mdy for date interpretation.
Two things really,
Firstly, you can control the expected date format for each connection. Before issuing the insert statement, do set dateformat dmy; or set dateformat mdy; as appropriate.
Secondly, it's always advisable to work with dates in the ISO format of YYYYMMDD, so if you insert the data '20210314' it will always be treated correctly.

sql date format "2019-10-30", "2019/10/30", "10-30-2019" and "10/30/2019"

I think it's no doubt that in sql "2019-10-30" is valid date format, and looks like "2019/10/30" accepted as well.
What about "10-30-2019" and "10/30/2019"?
I tried them in mariaDB and they're wrong format, but somehow I think I did see them in some sql tables. Please help me clarify the date format. Thanks
In MariaDB, the format for dates is yyyy-mm-dd. But MariaDB is quite lax and other formats are accepted; from the documentation:
A DATE string is a string in one of the following formats: 'YYYY-MM-DD' or 'YY-MM-DD'. Note that any punctuation character can be used as delimiter. All delimiters must consist of 1 character. Different delimiters can be used in the same string. Delimiters are optional (but if one delimiter is used, all delimiters must be used).
A DATE literal can also be an integer, in one of the following formats: YYYYMMDD or YYMMDD.
All the following DATE literals are valid, and they all represent the same value:
'19940101'
'940101'
'1994-01-01'
'94/01/01'
'1994-01/01'
'94:01!01'
19940101
940101
So, for the examples that you provided:
2019-10-30 -- ok: default format
2019/10/30 -- ok: format with alternative delimiter
10-30-2019 -- NOT ok
10/30/2019 -- NOT ok
You can translate a string to a date with function str_to_date().
str_to_date('10-30-2019', '%m-%d-%Y')
str_to_date('10/30/2019', '%m/%d/%Y')
What you are really doing is converting from a string representation of a date to an internal date time representation or data type. The format you are referring to is ISO 8601. The ISO date (2019-10-30 with hyphens or parentheses) format is usually the native or default string conversion that most databases use, that's why those formats work even if you don't specify the conversion. If you intend to convert from other formats you probably would need to specify them. Your default representation for your local settings might work too, but that depends on the specific database.

Specify string date format before casting in a function SQL

I have a scenario to cast string date into date format. But the date string is not in a straight format, so the conversion throws error. So what I tried is
set dateformat dmy
before the casting in sql and it worked without any issue.
But the trouble is I need this to implement in a view or function. But the disappointing part, function or view doesn't support set dateformat with which it says as side effecting operator
So how can I specify the date format of the given string before casting in a function or view?
The third parameter of CONVERT() allows to provide a format type.
Assuming your SET DATEFORMAT DMY I take you've to deal with dates like "1/2/2000", meaning the first of February in 2000.
Try this:
DECLARE #d VARCHAR(100)='1/2/2000';
SELECT CONVERT(DATE,#d,104)
The 104 is the German type with a 4-digit year. If this does not fit your needs, you can follow the link to find a better suiting format.
If you need further help, please provide samples of your actual dates.
Hint: You should always store a value in a column with the appropriate type. Storing dates as strings will make things slow and opens a lot of error sources...
As Damien wrote in his comment to the question, ideally you should not mess around with string representations of datetime in the first place - you should be using proper data types - and since you asked about creating a view, it can only mean that somewhere in your database there's a datetime value stored as a string.
The solution to this situation is to change the way you are storing this value - use DateTime2 for datetime values, Date for date-only values, or Time for time-of-day values.
Further reading - Aaron Bertrand's Bad habits to kick : choosing the wrong data type
Assuming you can't change the database design, read the rest of this answer.
You can't use set dateformat on a view or a function, but you can use convert instead of cast to change the string representation of a datetime value into an actual datetime value, assuming the string representation has one of the supported date formats (there are quite a few of them, so usually it shouldn't be a problem).
If your string representation of the datetime is in a format that is not supported by the built in convert function, you might need to do some extra work in the form of string manipulation to either change it into a supported format, or (in the harder case) separate the string representation to parts and then use datetimefromparts.
If you could provide the actual format you are using in your string representation of the datetime format I can probably edit this answer to show you exactly how to do it.
SELECT CONVERT(varchar(10),CAST('07/01/2018' AS DATE),23)
Result
2018-07-01
Not sure what you mean by, "date string is not in a straight format". Examples will help.
Have you tried parsing, instead of casting?
SELECT
TRY_PARSE(thedate AS datetime) as justParse
,TRY_PARSE(thedate AS datetime USING 'en-US') as parseUS
,TRY_PARSE(thedate AS datetime USING 'en-GB') as parseGB
,try_cast(thedate as date) as tryCast
FROM (values
('07/01/2018')
,('01/07/2018')
,('07 jan 2018')
,('jan 07 2018')
,('Monday, 7 January 2019')
)d(thedate)

DATEDIFF working on yyyymmdd format SQL server

Why the DATEDIFF accepts yyyymmdd format ? Isnt it only for yyyy-mm-dd format ?
The function DATEDIFF(datepart, start_date, end_date) is working fine when the dates are in yyyymmdd format e.g.
DATEDIFF(DAY, 20161201, 20161231);
It gives answer 30
and if you do DATEDIFF(DAY, 20161201, 20161231) + 1 -- end date inclusive
It gives 31
Thanks,
Aiden
This can be a bit hard to tease out, but it is explained in the documentation, in the section "Supported String Literal Formats for date".
There are five sections on this (but the last two are API specific). The first section is affected by internationalization settings and has a bunch of different formats.
The second is the ISO 8601 format. I think the hyphenated format conflicts with the very last format in the first table ("yyyy dd mm" without the hyphens).
The final section has this informative line "A six- or eight-digit string is always interpreted as ymd". Hence, 'YYYYMMDD' is always interpreted correctly. Hence, this is the unambiguous format for date/time.
Note: Because the functions you are using expect dates, if the integer works, then it is converted to a date using its string representation. Normally, date constants should be in single quotes.
Actually its the sql server default format of dates but you can format your dates according to your requirements by following the link:
http://www.sql-server-helper.com/sql-server-2012/format-function-vs-convert-function.aspx

SQL Server dateformat query

I realise that you can use SET DATEFORMAT to alter the way that a string is parsed but is the following unambiguous:
SELECT CONVERT(DATE, '02Oct15')
Is there any circumstances that this would be interpreted as 15th October 2002?
The century conversion will be an issue in 35 years (the y2k50, there is an amusing thought), but until then it's unambiguous. Any attempt to pass an invalid date in the first section results in a conversion error rather than it treating the third section as a date instead of a year.
Finally changing the default language (which changes the default date format) uses the same conversion (British), or causes it error out (Italian). Still as others have mentioned, storing dates in this format is a bad idea, however unless I miss my guess this seems like your importing data from a report, so you probably don't have much control over it. Anyway hope that helps and good luck.
I was not able to make 02Oct15 to become October 15, 2002. However, if all three date components are numbers, it's easy to make that cast:
SET DATEFORMAT YMD
SELECT CONVERT(DATE, '02Oct15'), -- October 2, 2015
CONVERT(DATE, '021015') -- October 15, 2002
I suspect that once you introduce natural language to the string, SQL Server use culture-specific rules to convert the date components. But in the end, only Microsoft knows what SQL Server's string-to-date algorithm is.