Unable to convert DateTime from SQL Server to C# DateTime - c#

I wrote a program in C# that uses dates. It takes the value from a SQL Server table. I was using Windows 7 and the program worked fine. I had this line of code:
DateTime fechaOperacion = Convert.ToDateTime(reader["FechaOperacion"]);
The reader returned a date in a 24h format and I was able to convert that to a DateTime variable.
Now I did a system upgrade to Windows 10 and that same line of code is throwing the following error:
String was not recognized as a valid DateTime. there is an unknown word starting at index 20.
And now the reader returns a.m. / p.m. format, and at index 20 there is a.m or p.m.
I have tried the following things:
Rephrasing the line of code to:
Convert.ToDateTime(reader["FechaOperacion"], System.Globalization.CultureInfo.InvariantCulture)
reader.GetDateTime(reader.GetOrdinal("FechaOperacion"));
Convert the culture to 24h format
System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo(1033);
But none of that seems to work, I don't know what else to do.

Ultimately, the underlying problem here is storing a value that represents a date/time as textual data (meaning, some kind of [n][var]char({max|n}), or at a push: [n]text). This has multiple problems:
it takes more space
it cannot be sorted correctly / efficiently
it cannot be indexed correctly / efficiently
it cannot be filtered correctly / efficiently
it leads to parsing errors between client and server
it has all sorts of localization and internationalization problems
What you should have is a datetime / date / time / etc column. This is then stored as a number (not a string) that requires zero parsing and will work reliably without any conversion problems.
Note: it could be that you are storing it correctly but formatting it inside the select statement of your query. In which case, just don't do that; return the date-time raw, and let the receiving client worry about how to display it.

Depending on your actual format, you can define a suitable format list and do a conversion like below
string[] mfs = { "MM/dd/yyyy HH:mm:ss", "MM/dd/yyyy h:mm:ss tt"};
var dat = DateTime.ParseExact("04/23/1945 8:45:22 PM", mfs,
System.Globalization.CultureInfo.InvariantCulture,
System.Globalization.DateTimeStyles.None);

Related

Date type in MySql

I'm new to MySQL and C#.
I stored certain values in a column with data type Date. I did not want the time, only the date to be stored.
On viewing these values using phpMyAdmin or MySql command line, I see them in the format:
YYYY-MM-DD
However, when I retrieve these values in to my web application, they are displayed in the following format:
YYYY-MM-DD HH:MM (the time is specifically 12:00).
Why does this happen? And how can I prevent this from happening?
when you store in C# your date field, you use DateTime object. In this object when you don't specify the time part will be put a default value depends on Globalization.
You can study how DateTime works here
You can convert the date to the format you like when you fetch the data, using date_format():
select date_format(datecol, '%Y-%m-%d')
This returns the value as a string.
You shouldn't retrieve the value as a string from mysql. Why? Because if you ever need to do any operations on that value, such as adding a day, then you will need to parse it back into a DateTime again. String parsing can be slow, and when it comes to dates they are prone to errors like misinterpretation of mm/dd/yyyy and dd/mm/yyyy formatting.
The problem you have is that .NET does not have just a Date type. It only has a DateTime type. So loading a MySQL DATE type, is going to get a DateTime with the time portion set to midnight.
There's no direct problem with that, except on how are outputting the result. If you just call .ToString() without any parameters, or you implicitly use it as a string, then you are going to get a result with the full date and time. You simply need to provide a parameter to indicate what formatting you want.
Without any parameters, you are getting the General "G" format. This is explained in the documentation here.
In other words:
yourDateTime.ToString() == yourDateTime.ToString("G")
You can read about all of the other formats available, here and here.
In particular, if you just want the date, then you probably want to do this:
yourDateTime.ToString("d")
Based on your comments, you should be doing this instead:
MySQL Query:
SELECT Gbstartdate FROM TblGbDef
C#:
DateTime gb_start_date = (DateTime) datareader[0];

SQL datetime to C# string and back to SQL datetime

I have a webservice method that gets data from sql of the format
2012-11-18 11:21:03 when i save it to C# string it becomes this format: 18.11.2012 11:21:03
How do i change it back to the SQL format 2012-11-18 11:21:03 ?
Parse it into a dateTime again
DateTime myTime = DateTime.Parse(myString);
and back into a proper to string
myTime.ToString("yyyy-MM-dd HH:mm:ss");
Or just read it into a datetime and cut out the middleman.
You can get the universally sortable string format (which looks like the one used by SQL server) by using the format string "u" like this:
var dateTimeString = String.Format("{0:u}", yourDateTime);
Simply run the below code,
var newDateTime = oldDateTime.Date.ToString("yyyy-MM-dd HH:mm:ss");
Its just converting it back to the SQL Format DATETIME
Trouble with Dates as strings is they are ambiguous and the formats can vary based on where you are in the world, or even local machine settings. You might assume a date string is yyyy-mm-dd but what if it is actually yyyy-dd-mm? Some dates will appear to work and some will be invalid.
In other words is 2013-02-10 the 10th of February or is it the 2nd of October? If it is just a string you have no way of knowing for sure what was intended.
Your best bet as suggested by #Haedrian is to store in a DateTime C# object, not a string. That way it is never ambiguous and you have access to various date specific functions. If you must store as a string you can convert back to a date as above or use
DateTime.TryParse(datestring, out dateVariable);
which won't throw an exception for an invalid format. Depends if you want exceptions!
Also I would suggest if you must use strings to use a 3 character month in strings, which again eliminates the ambiguity, e.g.
"dd-MMM-yy hh:mm tt"

changing date format before insertion to database

I'm uploading an excel file to a server and then inserting its rows and columns into a database. I'm doing it line by line but I have a problem with datetime. After inserting 146 rows of data I get an error which reads:
The conversion of a varchar data type to a datetime data type resulted in an out-of-range value.
The statement has been terminated.
The problem is its the date. In the excel files the dates are formatted dd/mm/yyyy but the the database is taking them as being mm/dd/yyyy so when the date does past the 12th I get the out-of-range errror. I dont want to change my excel files so is there an option I can change on the database (MS SQL-server) or do I have to use c# code which can convert them before they get inserted... Thanks...
If you know the format coming from Excel, you are best parsing the string to a DateTime in C# with a specific IFormatterProvider.
The problem here is there is no culture information on the string coming from Excel, so the conversion to a DateTime can only take into account the culture of the database - in this case a format that reverses the month and day. This will mean that dates outside the range (as in your case) or ambiguous dates will never parse correctly.
In C# code you are able to specify a culture that implements IFormatterProvider, en-GB has the date format of the Excel dates you specify. The example in the MSDN documentation shows how to do this. My example briefing shows how to convert a string with an en-GB date format into a DateTime that is culture agnostic:
var culture = CultureInfo.CreateSpecificCulture("en-GB");
var date = DateTime.Parse("13/12/2011", culture);
SQL has the same problem with culture. A string representation of any culture-sensitive data will always lose the current culture. When converting that data you need to specify the culture if it differs from the server.
You can do this in SQL and hard-code the format of the string you are trying to convert (103 represents en-GB date formats dd/mm/yyyy):
declare #datestring varchar(10) = '13/12/2011' --13th December
-- 103 is the format code for UK dates with full yyyy century.
select convert(date, #datestring, 103) --gives 2011-12-13
declare #datestring2 varchar(10) = '05/04/2011' --5th April, ambiguous date.
select convert(date, #datestring2, 103) --gives 2011-04-05
Convert / cast format codes.
It is also worth noting that this will also correctly convert ambiguous dates such as 05/04/2011, which would reverse the month/day if the culture wasn't known.
For example, if you tried to convert the UK 5th April 2011 into a US date without telling the parser what the format is, you will get 4th May 2011 as output - reversing the month and day.
You can do this before inserting with T-SQL :
set dateformat dmy
See http://msdn.microsoft.com/fr-fr/library/ms189491.aspx
You can do in database as well probably try to write a stored procedure that inserts your data to database using your excelsheet.
User below mentioned TSQL code in your SP and that will work.
CREATE PROCEDURE ABC
AS
-- Do some operation
SET DATEFORMAT ydm;
insert into #dates
select '2008-09-01','2008-09-01'
END
I think you have to do it in c#.
Try something like this:
String excelDate = ...
String[] dateParts = excelDate.Split('/');
String sqlDate = dateParts[1] + "/" + dateParts[0] + "/" + dateParts[2];
...
First parse your excel datetime to C# datetime object and format the datetime object as let's say
DateTime dt = DateTime.Parse(drExcel["dateofExcel"]);
drDB["DateTime"] = dt.ToString("s");
hopefully it will solve your problem

How to get date in C#, without localisation

My C# application have to read some date from MySQL database. Problem I have is that format of date depends on system localisation settings.
My question is if is possible that I always get date in formats yyyy-MM-dd hh:mm:ss, and yyyy-MM-dd, no matter of localisation settings.
Thank you in advance!
If you are storing the dates as true date or datetime values, your application will get the raw binary data back, and it will not be subject to localization until you create a string representation of the date values. My guess is that you are looking at the values in the debugger or using Console.WriteLine(theValue);, which will use the current locale. Always include the desired format and/or the desired culture when converting non-string values to strings.
If you are storing the dates as strings, you will always have to know exactly what format went into the database.
Assuming the dates are stored as date or datetime: just handle the values as they are, and don't convert them to strings until you need to show them to a user:
DateTime theValue = theReader.GetDateTime(fieldOrdinal);
var theValueAsText = theValue.ToString(CultureInfo.InvariantCulture);
var specificTextRepr = theValue.ToString("yyyy-MM-dd HH:mm:ss");
The theValueAsText variable will be a string representation that is not tied to a specific culture. The specificTextRepr will be your specific text representation.
You shouldn't be reading it back as a string from the database - you haven't shown how you're reading the data, but if you use something to populate a DataTable, or LINQ, or IDataReader.GetDateTime then there's no string formatting involved (assuming it's stored properly in the database, which it looks like it is).
A DateTime value doesn't intrinsically have a format, any more than an int is in decimal or hex - it's how you choose to convert it that matters, and you should almost always avoid doing that formatting unless you really need to.
Since you store the dates in date and date/time specific representations, formatting does not play into it at all (as opposed to some highly discouraged storage schemes when date/time is stored as strings, when formatting does matter, but for a wrong reason).
When you query MySQL from your C# code, you will get the correct dates no matter what your locale is. They will be displayed differently based on the locale, but they will represent the proper date regardless of the locale settings.
You can format the date directly in the query by using
date_format(dob,'%d/%m/%Y')
select date_format(dob,'%d/%m/%Y') dob from student where Id=1
Change
CurrentDate = DateTime.Now.ToString("MMM d, yyyy");
CurrentTime = DateTime.Now.ToString("hh:mm tt");
TO
CurrentDate = DateTime.Now.ToString("MMM d, yyyy",CultureInfo.InvariantCulture);
CurrentTime = DateTime.Now.ToString("hh:mm tt", CultureInfo.InvariantCulture);

String to DateTime in C# to save in SQL server

I have an issue while converting "March 16-17" to DateTime and saving it to SQL server. "March 16-17" as it looks, read as March 16 to March 17, which in my case is invalid, but C# DateTime.TryParse() is treating "March 16 -17" as March 16, 2017 which is wrong, and saving the data in SQL server. SQL server treats "March 16-17" as invalid. So, can some body tell me how to use SQL server datetime validation in C#.
Thanks
Ashwani
It sounds as if the value shouldn't be a DateTime at all. Instead it should be a string (varchar/nvarchar) or two DateTime values (start and end). I.e., why are you trying to call DateTime.TryParse or DateTime.TryParseExact in the first place? If you want to store them as dates, you'll need to force the users to enter them as dates (as in two date values in your example) and then you can easily store them as dates. If you want to allow users to enter "March 16-17" or "Spring 2010" or "Last half of March", then use a varchar or nvarchar data type.
EDIT Given what you have said in comments, it sounds like you are passing the XML directly to SQL Server and hoping to have SQL Server parse the dates. Unfortunately, SQL Server is not great a parsing as you have discovered. IMO, it would be easier to rebuild the XML in C#, validating and parsing dates and integers, before you pass it to SQL Server. I.e., I would try to do as little of this type parsing and validation in SQL Server as possible. If you still want to go that route, another solution would be to create a CLR function (which means the CLR must be enabled) that would give you the same date parsing functionality as C#.
EDIT After much discussion, it sounds like the issue is that C#'s date parser is too clever for your purposes. What you want is for C# to invalidate the date as SQL Server would. I can think of a couple of ways to solve that:
Send a long list of allowed formats to the DateTime.TryParseExact method. The downside is that this is far less forgiving in terms of parsing date values.
Run TryParse and validate the year. If the year X number of years beyond this year, then invalidate it.
Find a way of forcing the source of the XML to enforce dates so that only valid dates are sent.
Write a routine that determines if the date has some wonkiness to it like 16-17 (although 03-16-17 should be considered valid, so you will need to be careful) before you pass it to TryParse.
Trying to actually use SQL Server's date parsing will not work unless you push the data into a character column and then use SQL Server's IsDate and Cast functions to populate the DateTime column after you have populated the data.
Parsing
You can use DateTime.TryParseExact to parse a string to a DateTime, requiring it to be in an exact format. This will eliminate the problem, that you are able to parse an invalid date to a DateTime instance.
Here is an example:
DateTime dt;
if (DateTime.TryParseExact("March 16", "MMMM dd", new CultureInfo("en-GB"), DateTimeStyles.None, out dt))
Console.WriteLine(dt);
When omitting the year, TryParseExact will assume the current year. If you pass in "March 16-17" to that method, it will fail. The IFormatProvider parameter is the english culture, so we can parse "March" to be the 3rd month of the year.
As you note, this is not the same as what SQL Server does. How it converts dates will be based on it's collation settings. I would not recommend it, but if you really, really need to replicate that functionality exactly, and use it from C#, you could create a Stored Procedure that takes a varchar, makes the conversion, and returns DateTime - and call it from C#.
You can also use DateTime.TryParse method to parse the date from C#. This method also takes an IFormatProvider, which tells the framework how to do the parsing. IFormatProvider is implemented by CultureInfo, so if you pass in the CultureInfo that corresponds to the SQL Server collation where you observed the desired behavior, chances are that the parsing results will be similar. Finally, you could do your own implementation of IFormatProvider if you are unsatisfied with the built-in possibilities.
My Comments
Your real problem is that you are in effect doing the validation and transformation from string to DateTime twice. Once in C#, then you send the string to SQL Server, and have that transform it again. This is bound to give you problems, since, as you noted, the two systems parse similarly, but not exactly the same way in edge cases.
What I think you should do, is to do your validation and parsing in C#, and then send the resulting DateTime to SQL Server as a DateTime object, so SQL Server itself needs to do no parsing. You can do this using parameterized queries in ADO .NET - if you use something else for data access, there will be a similar feature.
I understand that you don't want to restrict your users. You sound like you're doing something like this:
mySqlCommand.CommandText = "UPDATE tbl SET date_field = #parm";
string maybeDate = "March 16-17");
DateTime dt;
if (DateTime.TryParse(maybeDate, dt)
{
mySqlCommand.Parameters.AddWithValue("#parm", maybeDate)
}
Can you do this instead?
mySqlCommand.CommandText = "UPDATE tbl SET date_field = #parm";
string maybeDate = "March 16-17");
DateTime dt;
if (DateTime.TryParse(maybeDate, dt)
{
mySqlCommand.Parameters.AddWithValue("#parm", dt); // <============
}
It thinks 17 is 2017 because years can be writen in 2 digits try forcing it to be four
if (DateTime.TryParseExact("March 16-17", "MMMM dd YYYY", new CultureInfo("en-GB"), DateTimeStyles.None, out dt))

Categories