Dateformat mismatch in sql server and C# code - sql-server

I have a problem.
I have an application in C# with SQL SERVER 2005 as backend.
The problem is in fetching the correct record based on the date.
The frontend code is
if (string.IsNullOrEmpty(txtFromDate.Text))
SelectCmd.Parameters[0].Value = DBNull.Value;
else
SelectCmd.Parameters[0].Value = txtFromDate.Text;
Now if I run usp_NewGetUserDetail '03/04/2010' in the query analyser, I am able to get the correct record.
So I am preety confident that my SP is correct(I have tested with many variations).
But if the same value is passed from front end code(SelectCmd.Parameters[0].Value = "03/04/2010";), I am getting some unexpected record. By that I mean , the records which are not in the date range.
I guess that there is some mismatch in date format of backend and frontend.
Kindly let me know if I missed out some information that I need to provide for solving this
Please help.

Dealing with dates on SQL Server is a tricky business, since most formats are language- and locale-dependent. As Adam already mention - you should try to avoid dealing with dates as strings - it does get messy, and using DateTime (both in .NET and in T-SQL) is much safer and easier.
But if you must use strings, then be aware of these points: a date like 02/05/2010 will be interpreted as Feb 5, 2010 in some places, or as May 2, 2010 in others. So whatever you're doing - you'll always run into someone who has a different setting and gets different results.
The way to do here is to use the ISO-8601 format which is independent of all locale and language settings and just always works.
So for your dates, always use the YYYYMMDD format - first of all, it always works, and second of all, with that format, you get a "natural" sort behavior - sorted by Year, then Month, then Day.

There's no need to pass the date as a string, nor should you. Set the value of the parameters to a DateTime object that represents the date you want, not the string representation of it.

Try something like this:
DateTime fromDate;
if (DateTime.TryParse(txtFromDate.Text, out fromDate))
{
SelectCmd.Parameters[0].Value = fromDate
}
else
{
SelectCmd.Parameters[0].Value = DBNull.Value;
}

Related

SQL Server not accepting YYYY-MM-DD

My local SQL Server 2016 setup at work decided not to accept the YMD date format after going through a reinstall. For example, the following query, that was and still is accepted in my coworkers' setups:
SELECT "id"
FROM test.dbo.tabEmp
WHERE "DateAdmission" <= '2021-12-31' AND "DateAdmission">= '2021-12-30' `
When I try to run it I see this:
The conversion of a varchar data type to a datetime data type resulted in an out-of-range value
however, if i rewrite the dates as 2021-31-12 and 2021-12-30, in the YYYY-DD-MM format, they are accepted.
I can't really convert or format it since the sql queries in our system are numerous and done so in a way that it would be nearly impossible to. Is there something that can be done? I tried changing windows' Date format but to no avail.
For the datetime and smalldatetime data types the format yyyy-MM-dd is not unambiguous (note that it is for the newer date and time data types). If you are not American, the date will very likely be interpreted as yyyy-dd-MM, and as there are not 31 months in the year you get an error.
For SQL Server, the formats that are unambiguous regardless of data type and language setting are yyyyMMdd and yyyy-MM-ddThh:mm:ss.nnnnnnn; ideally if you are using string literals use one of those formats as you can never get an error (unless you legitimately have an invalid date).
Otherwise you can explicitly CONVERT your value with a style code:
SELECT CONVERT(datetime, '2021-12-31', 126);
It seems that your new DB instance picked up a new language after the reinstallation.
The current language setting determines the language used on all system messages, as well as the date/time formats to use.
The date format setting affects the interpretation of character strings as they are converted
to date values for storage in the database. It does not affect the display of date data type values
that are stored in the database or the storage format.
You can run the following statement to return the language currently being used:
SELECT ##LANGUAGE;
This will tell us what the current language is and the date format (as well as a few other things):
DBCC USEROPTIONS;
Date format is modifiable via the following statements:
SET LANGUAGE us_english;
SET DATEFORMAT YMD;
Here is a good article on the subject: How to Change the Current Date Format in SQL Server (T-SQL)
It is also possible to modify SQL Server instance default language globally, once and for all: How to change default language for SQL Server?

Native Query date formats between different database engines

I am creating a native query for Hibernate using the following code
final Query countQuery = entityManager.createNativeQuery( countSql );
if ( countCriteria.getStartDate() != null ) {
final String startDate = countCriteria.getStartDate().toString();
countQuery.setParameter( START_DATE_PARAMETER, startDate );
}
Where startDate on my class is an org.joda.time.DateTime and toString() returns "2019-05-13".
These query parameters work fine in production, which is running against MS Sql Server. (ick!)
Now, the unit test is running against HSQLDB. I'm providing the same values and it throws:
javax.persistence.PersistenceException: org.hibernate.exception.DataException: data exception: invalid datetime format
When it attempts to run the query.
Since the parameter is formatted exactly the same, I'm assuming that the problem is the format of the date string for HSQLDB.
So, now what? How do I move forward with this? I've checked the setParameter format that takes TEMPORAL or whatever, but that won't work for JODA time.
I've already talked to my tech lead about not using native queries, but using hibernate queries, but it has fallen on deaf ears. Do I have another option so I don't have to battle my tech lead to write unit tests for our DAOs?
Well, I'm embarrassed to admit how long it took me to figure this one out.
I simply converted the LocalDate to a java date, then used that to set a TemporalType parameter.
Date date = localDate.toDate();
countQuery.setParameter(parmName, date, TemporalType.DATE);
This seems to be working fine.

LINQ converting date, need to handle bad date

I'm using LINQ-to-SQL and need to order by a date field. The date field is stored as text and could have anything in it since it is user entered data. I need to handle cases where an invalid date was placed in there.
For example, a date of "02/23/0000" returns:
The conversion of a varchar data type to a datetime data type resulted in an out-of-range value.
I need to avoid errors and I don't care where an invalid date like this gets sorted to. The parameters of the project mean I can't modify my source data, only read from it.
Here is an example LINQ statement.
from x in dbo_myTable
orderby Convert.ToDateTime(x.MyDateField)
select x
Do you definitely need to perform the ordering in the database? In this situation I would strongly consider pulling all of the data, then performing some conversion in .NET code where you have a great deal more control over what's going on, and then order it still in .NET code.
Ultimately, dealing with screwed up data in this sort of situation is tricky - the more control you have, the better.
You can do something like this (Based on your comment that they are all 10 characters)
from x in dbo_myTable
orderby x.MyDateField.Substring(6, 4), x.MyDateField.Substring(0, 2), x.MyDateField.Substring(3, 2)
select x
First is first; why cant you change the database to fix you obviously brokes table structure? Why cant you sanitize input when its going into the database? Why are you not validating user input?
Now for the answer; your only option is attempt to parse the date (with DateTime.TryParse or DateTime.TryParseExact) and set a default value of your choosing if it fails to parse:
from x in dbo_myTable
orderby TryConvertToDateTime(x.MyDateField)
select x
private DateTime TryConvertToDateTime(string dt)
{
DateTime rtn = DateTime.MinValue; // or whatever you want your default to be
DateTime.TryParse(dt,out rtn);
return rtn;
}

store one date and two time fields

I need to store schedule date and times. Scheduale contains one date field and two time fields.
Is there any possibility to store schedule in one db field and not in two (datetime + datetime)?
I am using SQL Server 2005.
Thanks!
Whether it is "start"+"stop", or "start"+""duration", you have 2 pieces of information = store 2 pieces of information.
Using a string or XML makes no sense: this requires take more space, more processing, more code to search and use.
Why would you want to store what are effectively two datetimes in one field rather than two? Are there no cases where the schedule might have times that cross days? (ie. 01/03/2011 23:59, 02/03/2011 01:35)? Do you not mind having to parse out the information rather than having it immediately ready for query?
If you really want to, there's no reason you can't store it as a string type, comma separated possibly, maybe XML as suggested, but I can't say it's recommended as date/time fields are more space efficient, nice and fast/flexible for searching purposes, and there are many useful T-SQL functions which can easily be used on date/time types which you'd be hard pushed to use on a string without some parsing and casting/converting.
If you can come up with a good reason for not using two datetime fields, I'll have another Donut! (ps. happy Fat Thursday).
One quick, and horribly evil thought ... you could use part of the datetime to store the "difference" ... sneak it into the "seconds" and "milliseconds" values, and apply it to the main date/time to get the new value. A bit hacky, but it'd could do the job, depending on your range requirements.
-- Example: 01/03/2011 12:30:02
-- Translates into - first of March 2011, 12:30 to 14:30 (12:30 + (seconds * hours))
set #ModifiedDatetime =
DATEADD(hour, DATEPART(second, #originalDateTime), #originalDateTime);
Beware of rounding errors with milliseconds ... and please think about the consequences of what you're doing. God kills a kitten each time someone abuses a type :)
You can try using the XML field type and store an XML snippet in there, similar to the following:
<schedule date="2011-01-01" fromTime="12:00" toTime="14:00" />
You can then use XQuery in a select to transform the result set back to a "normal" row-based result set. A sample query implementing XQuery, based on my example's XML schema, could be as follows:
SELECT
[...]
, Schedule.value('(/schedule/#date)[1]','datetime') as [Date]
, Schedule.value('(/schedule/#fromTime)[1]','char(5)') as [FromTime]
, Schedule.value('(/schedule/#toTime)[1]','char(5)') as [ToTime]
FROM [TABLE]
I'm not saying that storing it as XML is the best way to do it (as the other answers rightfully state), but you asked IF it is possible and I propose a solution...

Executing stored procedures with date parameters: Command Object vs Connection Object

When supplying dates to a stored procedure via a parameter I'm a little confused over which format to use for the dates. My original VBA syntax used the ADO Connection object to execute the stored procedure:
Set SentDetailRS = Me.ADOConnectionToIntegrity.Execute("dbo.s_SelectAggregatedSentDetailList '" & fCSQLDate(EffectiveDate) & "'", , adCmdText)
This works fine for me using the date syntax yyyy-mm-dd but when another user executes the code they recieve the error: 13 'Type Mismatch'.
After some experimentation I found that supplying the date in the format dd/mm/yyyy fixes this error for the user but now gives me the error!
Executing the stored procedure using a command object with parameters works regardless of the format of the date (I assume ADO is taking care of the formatting behind the scenes). I thought that using the format yyyy-mm-dd would work universally with SQL Server?
I'm also perplexed as to why this problem appears to be user specific? I noticed that my default language on SQL Server is 'English' whereas the other user's default language is 'British English', could that cause the problem?
I'm using ADO 2.8 with Access 2003 and SQL Server 2000, SQL Server login is via Windows integrated security.
Be careful, and do not believe that ADO is taking care of the problem. Universal SQL date format is 'YYYYMMDD', while both SQL and ACCESS are influenced by the regional settings of the machine in the way they display dates and convert them in character strings.
Do not forget that Date separator is # in Access, while it is ' in SQL
My best advice will be to systematically convert your Access #MM-DD-YYYY# (or similar) into 'YYYYMMDD' before sending the instruction to your server. You could build a small function such as:
Public function SQLdateFormat(x_date) as string
SQLDateFormat = _
trim(str(datePart("yyyy",x_date))) & _
right(str(datePart("m",date)),2) & _
right(str(datePart("d",date)),2)
''be carefull, you might get something like '2008 9 3'
SQLDateFormat = replace(functionSQLDateFormat," ","0")
'' you will have the expected '20080903'
End function
If you do not programmatically build your INSERT/UPDATE string before sending it to the server, I will then advise you to turn the regional settings of all the machines to the regional settings of the machine hosting SQL. You might also have to check if there is a specific date format on your SQL server (I am not sure). Personnaly, I solved this kind of localisation problems (it also happens when coma is used as a decimal separator in French) or SQL specific characters problems (when quotes or double quotes are in a string) by retreating the SQL instructions before sending them to the server.
I would guess that fCSQLDate function is culture-specific - i.e. it will parse the date based on the user's locale settings. That's why you see the problem.
Anyway, using queries with concatenated strings is always a bad idea (injection attacks). You are better off if you use parameters.
Access uses # as date field delimiter. The format should be #mm/dd/yyyy# probably the #mm-dd-yyyy# will also work fine.
Sorry I don't know mysql, but with oracle I would always explicity state the format that I was expecting the format to be in, eg: 'DD-MM-YYYY', to avoid (regional) date format problems
Why not use the format
dd mmm yyyy
There is only one way it can be interpreted.
You can use the Date() function to return a universal date based on the machine date and time settings. The region settings on the machine will determine how it it formatted on the client end. If you leave the field as strictle a DateTime field then the cleint region settings can format the date.
Going into the server, using the Date() function should aslo work (returning a universal date value).
Also, use a command object and parameters in your query when you pass them to avoid SQL injection attacks on string fields.

Resources