I have a legacy application where the input is a date string, i.e.:
06/12/2009
The format of the input is always a string, and is consistent, it's always dd/mm/yyyy
At the moment the legacy app just INSERTS this in a DateTime fields. Obviously if the Localization Culture settings of the Server change, we have a bug.
Two questions:
One:
Whats the safest way to store Dates in SQLServer in this situation?
Is there a format that will always be correctly interpreted regardless of the order of day and month?
Two:
What settings exactly determines the culture of a SQLServer DB, is it an OS setting, or a setting of that DB, or what?
cheers
Format YYYY-MM-DD is unambiguous, meaning that SQL Server won't confuse the month
and day when converting a string value to DATETIME. (I've never experienced a problem with an implicit conversion using that format using the four digit year.)
The "safest" (and most convenient) way to store date values in SQL Server is to use DATETIME datatype.
Use the CONVERT function to explicitly specify the input and output formats when converting between DATETIME and strings.
SQL Server 2005 Documentation on CONVERT style argument values:
http://msdn.microsoft.com/en-us/library/ms187928(SQL.90).aspx
To convert a string representation to DATETIME datatype:
select CONVERT(datetime, '2009-06-03', 20)
The first argument is datatype to convert to, the second argument is the expression to be converted, the third argument is the style.
(style 20 is ODBC Canonical format = 'YYYY-MM-DD HH:MI:SS' (24 hour clock)
[FOLLOWUP]
To convert a DATETIME expression (e.g. getdate() to VARCHAR in 'YYYY-MM-DD' format:
select CONVERT(varchar(10), getdate(), 20)
Note that specifying varchar(10) gets you just the first 10 characters of the etnire 'YYYY-MM-DD HH:MM:SS' format.
[/FOLLOWUP]
As to what determines the default formats, that's going to be research. We avoid the issues caused by default formats by specifying the formats.
I would recommend storing all dates in UTC time when they are placed into the database. It will be consistent that way.
Storing dates like this seems to work well...
YYYY-MM-DD
See SET DATEFORMAT. The SQL 'culture' is set by SET LANGUAGE at a session level. SQL Server has its own date format settings, independent of the hosting OS. This is for several reasons: ANSI compliance, to prevent OS changes from affecting applications using the database hosted on that host and not least is compatibility, the SQL long predates the OS is currently running on.
Keep in mind that DATA is not its PRESENTATION. In this case that DATA is a DATE or DATETIME, regardless of how you show them.
As for inserting/updating/comparing datetime values, I quote the BOL:
When specifying dates in comparisons
or for input to INSERT or UPDATE
statements, use constants that are
interpreted the same for all language
settings: ADO, OLE DB, and ODBC
applications should use the ODBC
timestamp, date, and time escape
clauses of:
{ ts 'yyyy-mm-dd
hh:mm:ss[.fff] '} such as: { ts
'1998-09-24 10:02:20' }
{ d 'yyyy-mm-dd'} such as: { d '1998-09-24' }
{ t 'hh:mm:ss'} such as: { t '10:02:20'}
I can assure you that, if you use this formats they will always work, regardless of the locale of you server
I'm a bit conservative in these matters, but I prefer to use separate Year / Month / Day fields in the table, rather than a Date field that uses a DBMS-specific data type. It certainly takes more space, but the lack of ambiguity and increased portability is worth it to me.
The price you pay is that you don't get free date/time arithmetic and sorting, but it's easy enough to do yourself or by a slightly more complex "ORDER BY" clause.
I agree with the advice from spencer7593, but please be aware that using cast or convert without a format can give unexpected results. This T-SQL query returns 12, not 1.
set language British
select month(CAST('2016-01-12' AS datetime))
Normally I prefer to insert as
insert into tbl values('yyyyMMdd')
Then, itll be inserted in proper format based on db.
Related
I have SQL which I run against the on premises database. In the WHERE clause I am narrowing it down to year
WHERE YEAR(SRCSYS_ADD_DATE_TIME)=2020
and I get the results
In Snowflake work sheet I am using
WHERE EXTRACT(YEAR FROM TO_DATE(SRCSYS_ADD_DATE_TIME))=2020
and I am getting this message
Date '2020-05-28-20.42.09.724117' is not recognized'
Please need help.
Snowflake's automatic date-time parsing isn't recognizing your period separated timestamp formatting.
You'll need to explicitly specify a format to read the string during conversion:
EXTRACT(
YEAR FROM
TO_DATE('2020-05-28-20.42.09.724117', 'YYYY-MM-DD-HH24.MI.SS.FF')
) = 2020
bkan.
The problem is the timestamp format. If you don't specify a timestamp format, Snowflake will try to autodetect. In this case it can't, so you'll have to specify the timestamp format:
select year(to_timestamp('2020-05-28-20.42.09.724117', 'YYYY-MM-DD-HH24.MI.SS.FF6'));
If you don't want to specify the timestamp format, your best option is using YYYY-MM-DD HH24:MM:SS.FFFFF (or some other precision of fractional seconds) like this:
select year('2020-05-28 20:42:09.724117'::timestamp);
The second option reformats the timestamp to the standard format, and the ::timestamp syntax casts it to a timestamp.
I have a rather basic question out of interest. In T-SQL (SSMS or the like), what is the difference, "behind the scenes", between using dd-mm-yyyy and yyyy-mm-dd in a where statement.
For example, these two queries give me different results
select * from DB..table where application_date > '01-01-2019' and application_date < '01-06-2019' order by app_ID;
select * from DB..table where application_date > '2019-01-01' and application_date < '2019-06-01' order by app_ID;
It seems that the first is a sub set of the second.
For comparison, the first gives me 83 records, while the second gives me over 11 thousand with change.
It would be interesting to understand, if someone could enlighten me.
String representations of datetime values are culture dependent.
In USA, for instance, the string representation format is MM/dd/yyyy, while in UK it's dd/MM/yyyy.
This means that SQL Server will convert string literals to datetime based on the culture settings, specifically, it's DATEFORMAT - Unless the string representation format complies to the ISO 8601 standard - which is either yyyy-MM-ddTHH:mm:ss or yyyyMMddTHHmmss.
However, there is a little known bug (or feature) with the DateTime data type, when converting date-only values from string formatted as yyyy-MM-dd, the conversion still depends on the culture settings - while converting from the alternate ISO 8601 format yyyyMMdd is perfectly safe for all datetime data types.
This is probably because this format is not unique to ISO 8601 - it's also a part of the ODBC canonical format - which is yyyy-MM-dd HH:mm:ss - almost the same as ISO 8601, just with a space instead of the T as a separator between the date part and the time part.
This bug only exists in the DateTime data type, and is one of several reasons why you should always prefer to work with the newer and improved DateTime2 data type.
for more information, read Date conversion and culture: Difference between DATE and DATETIME.
TL;DR;
The only safe string representation date format to work with datetime is yyyyMMdd.
all other formats conversions are culture dependent and might yield errors or worst - wrong results.
Main points:
When you can, prefer DateTime2 over datetime.
When you can, prefer avoiding string representations of datetime.
When you have to work with string representations of datetime, Always work with one of the ISO 8601 formats - either yyyy-MM-ddTHH:mm:ss or yyyyMMddTHHmmss
When you have to work with DateTime and string representations of date only, always use yyyyMMdd.
The literal '01-06-2019' is actually interpreted to be 2019-01-06, which is not the same thing as 2019-06-01, which the second query is using.
You may read SQL Server's documentation covering supported date literal formats. But in general, try to stick with ISO date formats, which are supported by pretty much every SQL database. So, the second version of your query is the one you should always try to use.
I would like to keep my dates as datetime datatype by also be in MM/DD/YYYY format. I know how to do this by converting them to a varchar, but want to keep the datetime format. Can anyone help with this?
Currently I have tried
SELECT CONVERT(datetime, GETDATE(), 101)
which is not working...
There is a basic misunderstanding in your question. Repeat after me: Datetimes don't have a format.
It helps if you think of them as just an array of seven integers (year, month, day, hours, minutes, seconds, milliseconds) with certain constraints. That's not in any way accurate, but it helps to get the notion out of your head that something akin to 12/31/2015 is stored in your database.
Datetimes only get a format when (implicitly or explicitly) being converted to strings. You already know how to set the format when explicitly converting to string, now all that is left to do is to find the implicit conversion that is obviously bothering you and replace it with an explicit one.
Date and datetime Values stored in the database are NOT in any recognizable format. They are stored in binary (1s and 0s) in a proprietary format where one part represents the number of days since a defined reference date (1 jan 1900) in SQL server). and the other part represents the time portion of the value. (in sql server, its the number of 1/300ths of a second since midnight.)
ALL formatting of dates and date times, no matter what format you wish for, is done only after the values have been extracted from the database, before you see them on screen, in whatever application you are using.
You can find all the formats that the SQL Server convert function can use on this MSDN Convert Link
I have a question about MS SQL Server string-to-datetime implicit conversion.
Specifically, can I be sure that a string in the 'yyyy-mm-dd hh:mm:ss' (e.g '2011-04-28 13:01:45') format, inserted into the datetime column, will always be automatically converted to a datetime type, no matter what regional or language settings are used on the server?
If no, does there exist such an independent string format for date time?
Does it depend on MSSQL server version and how?
thank you in advance
No.
If you're using a datetime column (as opposed to the newer types introduced in 2008), the safe format includes the letter T between the date and time components, e.g. '2011-04-28T13:01:45'.
For an ambiguous date (where the day <= 12), SQL Server can confuse day and month:
set language british
select MONTH(CONVERT(datetime,'2011-04-05 13:01:45'))
----
5
set language british
select MONTH(CONVERT(datetime,'2011-04-05T13:01:45'))
----
4
More generally, however, you should find a way to avoid treating datetime values as strings in the first place, e.g. if you're passing this value from some other (non-SQL) code, then use whatever facilities are available in your data access library (e.g. ADO.Net) to pass the value across as a datetime value - let the library deal with any necessary translations.
I need to take data between certain dates. But I get the following error.
AdsDateStarted : 03/18/2010 01:51:38.000 AM
AdsDateENded : 09/13/2010 05:00:00.000 PM
formatdate function converts today's date to 3/22/2010 format.
SQL = "SELECT * FROM Ads"
SQL = SQL & " WHERE AdsActive = 1 AND AdsAreasID = "& rtt &" AND CONVERT(VARCHAR(10), AdsDateStarted, 101) <= "& formatdate(Date()) &" AND CONVERT(VARCHAR(10), AdsDateEnded, 101) >= "& formatdate(Date()) &""
Set kdFonksiyon = objConn.Execute(SQL)
THe reason is that you have forgotten the apostrophes around the dates, so you get an expression like 3/22/2010 instead of a date literal like '3/22/2010'. The expression evaluates to an int value, so the database tries to convert the varchar values to int values also in order to compare them.
Instead of inserting the date in the query as a string, you should use parameters. Then you don't have to bother with apostrophes, but more importantly you don't have to guess what date format the database might accept.
As you use the dates as strings, there is no problem with parsing the strings to dates as the code is written now, but as you have chosen a date format that is not comparable as strings, your comparison will not work properly. If you want to compare dates as strings, you have to use an ISO 8601 format like 2010-03-22 that is comparable as strings, or preferrably compare the dates as proper dates, which is faster. (Even a lot faster if an index can be used.)
One of the immediate problems is that you need to put single quotes around the date values you are concatenating into the SQL string. Also, try to avoid any datetime conversion issues by using a standard ISO format like: yyyy-mm-dd
I would however strongly recommend you parameterise the query instead of building it up dynamically like this. So for example...
SQL = "SELECT * FROM Ads WHERE AdsActive=1 AND AdsAreasID = #rtt AND....."
And then pass in the values as parameters to the query. This will help with performance (execution plan reuse) and security (helps guard against SQL injection).
Use DateTime type parameters, please, and do not put together the date and time as a string.
If you HAVE to do that, use the international form that is accepted everywhree: 2010-03-22
Your problem is most likely different locales between client and server. You format as 3/22 and the server understands "day 3 of the 22nd month".
This is bypassed by using parameters of the language neutral iso form, as indicated above.
SQL Server recognizes 'yyyyMMdd hh:mm:ss' as a valid date time and lets you compare in this format. So if your formatDateTime function returns date in yyyyMMdd format that would do. You do not require to do a CONVERT on AdsDateStarted & AdsDateEnded.
Example:
SELECT * FROM Ads WHERE AdsDateStarted > '20100101' AND AdsDateEnded <= '20100321 11:59:59'
This query would retrieve all the records matching the date condition.