简体   繁体   中英

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

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.

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). Ie, 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. Ie, 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.

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); // <============
}

它认为17是2017年,因为可以用2位数字写年份,尝试将其强制为4

if (DateTime.TryParseExact("March 16-17", "MMMM dd YYYY", new CultureInfo("en-GB"), DateTimeStyles.None, out dt))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM