DateTime.Parse False positives with string containing dotted separated numbers - c#

I'm parsing datetimes from a text read from SQL Server using DateTime.Parse.
String like these:
5.4.1
1.1.4
12.1.13
were identified as dates, while they are not.
I can't use DateTime.TryParseExact(), since I have to load data in different formats:
dd/mm/yy
dd/mm/yyyy
dd MMM YYYY
dd-mm-yyyy
dd.mm.yyyy
How can I parse dates according to those formats, while ignoring values like shown above?

If we use the dates you have specified you can reach a result with the code below.
See also https://msdn.microsoft.com/en-us/library/h9b85w22(v=vs.110).aspx since it is very well explained.
string[] formats= {"dd/MM/yy","dd/MM/yyyy","dd MMM YYYY","dd-MM-yyyy","dd.MM.yyyy","dd.M.yy","d.M.y"};
string[] dateStrings = {"5.4.1","1.1.4","12.1.13"};
DateTime dateValue;
foreach (string dateString in dateStrings)
{
if (DateTime.TryParseExact(dateString, formats,
new System.Globalization.CultureInfo("en-US"),
System.Globalization.DateTimeStyles.None,
out dateValue))
Console.WriteLine("Converted '{0}' to {1}.", dateString, dateValue);
else
Console.WriteLine("Unable to convert '{0}' to a date.", dateString);
This code will result in:
Converted '5.4.1' to 1/5/2001 12:04:00 AM.
Converted '1.1.4' to 1/1/2004 12:01:00 AM.
Converted '12.1.13' to 1/12/2013 12:01:00 AM.
Please notice the cultureinfo! This can give different outputs according to it's setting. For example: month and date can be switched!
Ps. You can immediately try this working snippet on http://csharppad.com/.

You can let dates be parsed according to your expected formats. Just pass the (fixed, mm != MM) formats to TryParseExact():
string[] formats = { "dd/MM/yy", "dd/MM/yyyy", "dd MMM YYYY", "dd-MM-yyyy", "dd.MM.yyyy" };
string[] dateStrings = { "5.4.1", "1.1.4", "12.1.13", "23.02.2016" };
foreach (var dateString in dateStrings)
{
DateTime parsedDate;
if (DateTime.TryParseExact(dateString, formats, null, DateTimeStyles.None, out parsedDate))
{
Console.WriteLine("{0} was parsed as a valid DateTime: {1}", dateString, parsedDate);
}
else
{
Console.WriteLine("{0} was not parsed as a valid DateTime.", dateString);
}
}

Related

Why DateTime.TryParseExact is not working?

I am reading date from Excel and stored it in a variable In_Date,
formats with which the date is to be compared is stored in Valid_Date_Formats
In_Date = "08/01/2020 00:00:00"
Valid_Date_Formats is an array which stores multiple date formats.
I am checking the format in if condition but it always fails.
If(DateTime.TryParseExact(In_Date, Valid_Date_Formats,
System.Globalization.CultureInfo.InvariantCulture,
System.Globalization.DateTimeStyles.None,
DateTime_PlaceHolder))
What am I doing wrong here.
The input string has the following format: dd/MM/yyyy HH:mm:ss, which is missing from Valid_Date_Formats. (I'm assuming the 08 here is the day, because all your other formats start with the date part.)
The following returns the correct date:
DateTime.ParseExact("08/01/2020 00:00:00", new[] { "dd/MM/yyyy HH:mm:ss" }, CultureInfo.InvariantCulture, DateTimeStyles.None)
In response to your comment: I'm not aware of a built-in method that would tell you which exact format string was used. If you really need to find out, I guess you could traverse the formats until you find a match:
string[] formats = new[] { "dd/MM/yyyy", "dd/MM/yyyy HH:mm:ss" };
string input = "08/01/2020 00:00:00";
string usedFormat = null;
DateTime date;
foreach (string format in formats)
{
if (DateTime.TryParseExact(input, format, CultureInfo.InvariantCulture, DateTimeStyles.None, out date))
{
usedFormat = format;
break;
}
}

Conflict in system time format and database return time string value format in C#

I was using DateTime.ParseExact to convert my date string value to Date object.
Here is the code that I use to convert my date string to DateTime object.
DateTime.ParseExact(“ my date string value from database ”, "dd/MM/yyyy HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture) ;
My database returns a string value like this “25/9/2016 00:00:00”.
But when I was debug my code it continuously gave me that string is not valid string to convert to DateTime object.
Finality I have to change my laptop date time format to “d/M/yyyy H:mm:ss” to make my database string value to valid string value.
So how can I guarantee that my code work in server. What is the solution for this kind of situations ?? Do I have to check server date time format and change to format string according to it before build my code.??
ParseExact with the format "dd/MM/yyyy HH:mm:ss" will fail when you give it the string “25/9/2016 00:00:00” because the month is just a single digit.
Changing the format to "dd/M/yyyy HH:mm:ss" is the correct solution.
However, you shouldn't be storing dates & times in your database as strings as you will keep encountering this sort of problem. One of the main causes will be different settings when the date to string conversion happens. The main ones will be day-month-year vs month-day-year and single vs double digits for the days and months. Also if you're converting to local time rather than UTC then events will appear out of order in the database if you have users in different time zones.
If you really have to have strings then you can use the overload of ParseExact that takes an array of allowable formats so you can cope with multiple formats as in the example from that page:
string[] formats= {"M/d/yyyy h:mm:ss tt", "M/d/yyyy h:mm tt",
"MM/dd/yyyy hh:mm:ss", "M/d/yyyy h:mm:ss",
"M/d/yyyy hh:mm tt", "M/d/yyyy hh tt",
"M/d/yyyy h:mm", "M/d/yyyy h:mm",
"MM/dd/yyyy hh:mm", "M/dd/yyyy hh:mm",
"MM/d/yyyy HH:mm:ss.ffffff" };
string[] dateStrings = {"5/1/2009 6:32 PM", "05/01/2009 6:32:05 PM",
"5/1/2009 6:32:00", "05/01/2009 06:32",
"05/01/2009 06:32:00 PM", "05/01/2009 06:32:00",
"08/28/2015 16:17:39.125", "08/28/2015 16:17:39.125000" };
DateTime dateValue;
foreach (string dateString in dateStrings)
{
try {
dateValue = DateTime.ParseExact(dateString, formats,
new CultureInfo("en-US"),
DateTimeStyles.None);
Console.WriteLine("Converted '{0}' to {1}.", dateString, dateValue);
}
catch (FormatException) {
Console.WriteLine("Unable to convert '{0}' to a date.", dateString);
}
}

Check if a string is a valid date using DateTime.TryParse

I am using DateTime.TryParse() function to check if a particular string is a valid datetime not depending on any cultures.
To my surprise , the function returns true for even strings like "1-1", "1/1" .etc.
How can I solve this problem?
Update:
Does it mean, if I want to check if a particular string is valid datetime, I need a huge array of formats?? There will be different combinations , I believe.
Even there are lots of date separator ( '.' , '/' , '-', etc..) depending on the culture, it will be difficult for me to define an array of format to check against .
Basically, I want to check if a particular string contains AT LEAST day(1 through 31 or 01 through 31),month(1 through 12 or 01 through 12) and year(yyyy or yy) in any order, with any date separator , what will be the solution?
So, if the value includes any parts of time, it should return true too.
I could NOT be able to define a array of format.
If you want your dates to conform a particular format or formats then use DateTime.TryParseExact otherwise that is the default behaviour of DateTime.TryParse
DateTime.TryParse
This method tries to ignore unrecognized data, if possible, and
fills in missing month, day, and year information with the current
date. If s contains only a date and no time, this method assumes the
time is 12:00 midnight. If s includes a date component with a
two-digit year, it is converted to a year in the current culture's
current calendar based on the value of the Calendar.TwoDigitYearMax
property. Any leading, inner, or trailing white space character in s
is ignored.
If you want to confirm against multiple formats then look at DateTime.TryParseExact Method (String, String[], IFormatProvider, DateTimeStyles, DateTime) overload. Example from the same link:
string[] formats= {"M/d/yyyy h:mm:ss tt", "M/d/yyyy h:mm tt",
"MM/dd/yyyy hh:mm:ss", "M/d/yyyy h:mm:ss",
"M/d/yyyy hh:mm tt", "M/d/yyyy hh tt",
"M/d/yyyy h:mm", "M/d/yyyy h:mm",
"MM/dd/yyyy hh:mm", "M/dd/yyyy hh:mm"};
string[] dateStrings = {"5/1/2009 6:32 PM", "05/01/2009 6:32:05 PM",
"5/1/2009 6:32:00", "05/01/2009 06:32",
"05/01/2009 06:32:00 PM", "05/01/2009 06:32:00"};
DateTime dateValue;
foreach (string dateString in dateStrings)
{
if (DateTime.TryParseExact(dateString, formats,
new CultureInfo("en-US"),
DateTimeStyles.None,
out dateValue))
Console.WriteLine("Converted '{0}' to {1}.", dateString, dateValue);
else
Console.WriteLine("Unable to convert '{0}' to a date.", dateString);
}
// The example displays the following output:
// Converted '5/1/2009 6:32 PM' to 5/1/2009 6:32:00 PM.
// Converted '05/01/2009 6:32:05 PM' to 5/1/2009 6:32:05 PM.
// Converted '5/1/2009 6:32:00' to 5/1/2009 6:32:00 AM.
// Converted '05/01/2009 06:32' to 5/1/2009 6:32:00 AM.
// Converted '05/01/2009 06:32:00 PM' to 5/1/2009 6:32:00 PM.
// Converted '05/01/2009 06:32:00' to 5/1/2009 6:32:00 AM.
Use DateTime.TryParseExact() if you want to match against a specific date format
string format = "ddd dd MMM h:mm tt yyyy";
DateTime dateTime;
if (DateTime.TryParseExact(dateString, format, CultureInfo.InvariantCulture,
DateTimeStyles.None, out dateTime))
{
Console.WriteLine(dateTime);
}
else
{
Console.WriteLine("Not a date");
}
[TestCase("11/08/1995", Result= true)]
[TestCase("1-1", Result = false)]
[TestCase("1/1", Result = false)]
public bool IsValidDateTimeTest(string dateTime)
{
string[] formats = { "MM/dd/yyyy" };
DateTime parsedDateTime;
return DateTime.TryParseExact(dateTime, formats, new CultureInfo("en-US"),
DateTimeStyles.None, out parsedDateTime);
}
Simply specify the date time formats that you wish to accept in the array named formats.
So this question has been answered but to me the code used is not simple enough or complete. To me this bit here is what I was looking for and possibly some other people will like this as well.
string dateString = "198101";
if (DateTime.TryParse(dateString, out DateTime Temp) == true)
{
//do stuff
}
The output is stored in Temp and not needed afterwards, datestring is the input string to be tested.
An alternative is to create a method to validate that the text is of Date type.
public bool IsDateTime(string date)
{
if (string.IsNullOrEmpty(date)) return false;
return DateTime.TryParse(date, out DateTime dateTime);
}
Basically, I want to check if a particular string contains AT LEAST day(1 through 31 or 01 through 31),month(1 through 12 or 01 through 12) and year(yyyy or yy) in any order, with any date separator , what will be the solution?
So, if the value includes any parts of time, it should return true too. I could NOT be able to define a array of format.
When I was in a similar situation, here is what I did:
Gather all the formats my system is expected to support.
Looked at what is common or can be generalize.
Learned to create REGEX (It is an investment of time initially but pays off once you create one or two on your own). Also do not try to build REGEX for all formats in one go, follow incremental process.
I created REGEX to cover as many format as possible.
For few cases, not to make REGEX extra complex, I covered it through DateTime.Parse() method.
With the combination of both Parse as well as REGEX i was able to validate the input is correct/as expected.
This http://www.codeproject.com/Articles/13255/Validation-with-Regular-Expressions-Made-Simple
was really helpful both for understanding as well as validation the syntax for each format.
My 2 cents if it helps....
Try using
DateTime.ParseExact(
txtPaymentSummaryBeginDate.Text.Trim(),
"MM/dd/yyyy",
System.Globalization.CultureInfo.InvariantCulture
);
It throws an exception if the input string is not in proper format, so in the catch section you can return false;

DateTime.TryParse issue with dates of yyyy-dd-MM format

I have the following date in string format "2011-29-01 12:00 am" . Now I am trying to convert that to datetime format with the following code:
DateTime.TryParse(dateTime, out dt);
But I am alwayws getting dt as {1/1/0001 12:00:00 AM} , Can you please tell me why ? and how can I convert that string to date.
EDIT: I just saw everybody mentioned to use format argument. I will mention now that I can't use the format parameter as I have some setting to select the custom dateformat what user wants, and based on that user is able to get the date in textbox in that format automatically via jQuery datepicker.
This should work based on your example "2011-29-01 12:00 am"
DateTime dt;
DateTime.TryParseExact(dateTime,
"yyyy-dd-MM hh:mm tt",
CultureInfo.InvariantCulture,
DateTimeStyles.None,
out dt);
You need to use the ParseExact method. This takes a string as its second argument that specifies the format the datetime is in, for example:
// Parse date and time with custom specifier.
dateString = "2011-29-01 12:00 am";
format = "yyyy-dd-MM h:mm tt";
try
{
result = DateTime.ParseExact(dateString, format, provider);
Console.WriteLine("{0} converts to {1}.", dateString, result.ToString());
}
catch (FormatException)
{
Console.WriteLine("{0} is not in the correct format.", dateString);
}
If the user can specify a format in the UI, then you need to translate that to a string you can pass into this method. You can do that by either allowing the user to enter the format string directly - though this means that the conversion is more likely to fail as they will enter an invalid format string - or having a combo box that presents them with the possible choices and you set up the format strings for these choices.
If it's likely that the input will be incorrect (user input for example) it would be better to use TryParseExact rather than use exceptions to handle the error case:
// Parse date and time with custom specifier.
dateString = "2011-29-01 12:00 am";
format = "yyyy-dd-MM h:mm tt";
DateTime result;
if (DateTime.TryParseExact(dateString, format, provider, DateTimeStyles.None, out result))
{
Console.WriteLine("{0} converts to {1}.", dateString, result.ToString());
}
else
{
Console.WriteLine("{0} is not in the correct format.", dateString);
}
A better alternative might be to not present the user with a choice of date formats, but use the overload that takes an array of formats:
// A list of possible American date formats - swap M and d for European formats
string[] formats= {"M/d/yyyy h:mm:ss tt", "M/d/yyyy h:mm tt",
"MM/dd/yyyy hh:mm:ss", "M/d/yyyy h:mm:ss",
"M/d/yyyy hh:mm tt", "M/d/yyyy hh tt",
"M/d/yyyy h:mm", "M/d/yyyy h:mm",
"MM/dd/yyyy hh:mm", "M/dd/yyyy hh:mm",
"MM/d/yyyy HH:mm:ss.ffffff" };
string dateString; // The string the date gets read into
try
{
dateValue = DateTime.ParseExact(dateString, formats,
new CultureInfo("en-US"),
DateTimeStyles.None);
Console.WriteLine("Converted '{0}' to {1}.", dateString, dateValue);
}
catch (FormatException)
{
Console.WriteLine("Unable to convert '{0}' to a date.", dateString);
}
If you read the possible formats out of a configuration file or database then you can add to these as you encounter all the different ways people want to enter dates.
The main drawback with this approach is that you will still have ambiguous dates. The formats are tried in order so no matter what it'll try the European format before the American (or vice versa) and cover anything where the day is less than 13 to a European formatted date even if the user thought they were entering an American formatted date.
Try using safe TryParseExact method
DateTime temp;
string date = "2011-29-01 12:00 am";
DateTime.TryParseExact(date, "yyyy-dd-MM hh:mm tt", CultureInfo.InvariantCulture, DateTimeStyles.None, out temp);
From DateTime on msdn:
Type: System.DateTime% When this method returns, contains the DateTime
value equivalent to the date and time contained in s, if the
conversion succeeded, or MinValue if the conversion failed. The
conversion fails if the s parameter is null, is an empty string (""),
or does not contain a valid string representation of a date and time.
This parameter is passed uninitialized.
Use parseexact with the format string "yyyy-dd-MM hh:mm tt" instead.
That works:
DateTime dt = DateTime.ParseExact("2011-29-01 12:00 am", "yyyy-dd-MM hh:mm tt", System.Globalization.CultureInfo.InvariantCulture);
DateTime dt = DateTime.ParseExact("11-22-2012 12:00 am", "MM-dd-yyyy hh:mm tt", System.Globalization.CultureInfo.InvariantCulture);
If you give the user the opportunity to change the date/time format, then you'll have to create a corresponding format string to use for parsing. If you know the possible date formats (i.e. the user has to select from a list), then this is much easier because you can create those format strings at compile time.
If you let the user do free-format design of the date/time format, then you'll have to create the corresponding DateTime format strings at runtime.

DateTime.TryParse all possible type of dates

I want to check if a date has a correct format. There is many possibilities of correct dates like:
02.08.2010
2.8.2010
02.8.2010 02.08
02.August
...
I can test each on with code like this:
if (DateTime.TryParse(DateTime.ParseExact(date, "dd.M.",
new CultureInfo("sl-SI")).ToString(), out dt))
But then I can have 40 if statements. Is it possible to check all dates with one if statement or one loop?
Update:
Based on the answers so far, I am testing this code, but I have one more problem. What if I have just 9.2 not 9.2.2010 then this code will not work:
CultureInfo ci = CultureInfo.GetCultureInfo("sl-SI");
string[] fmts = ci.DateTimeFormat.GetAllDateTimePatterns();
if (DateTime.TryParseExact(date, fmts, ci, DateTimeStyles.AssumeLocal, out dt))
{
DateTime = Convert.ToDateTime(date);
Check = true;
}
Must I manually add this times or what can I do?
You can use something like the following, but be aware that more than one format might be able to parse the same date. For example 10/11/12 can be parsed as yy/MM/dd or MM/dd/yy, which are both valid US date formats. MM/dd/yy is more common, so it appears first in the list and is the one returned by the code below (if you use it with a US culture instead of the culture in the example).
string testValue = "10.11.12";
DateTime result;
CultureInfo ci = CultureInfo.GetCultureInfo("sl-SI");
string[] fmts = ci.DateTimeFormat.GetAllDateTimePatterns();
Console.WriteLine(String.Join("\r\n", fmts));
if (DateTime.TryParseExact(testValue, fmts, ci,
DateTimeStyles.AssumeLocal, out result))
{
Console.WriteLine(result.ToLongDateString());
}
Yes ParseExact can take a list of formats to check against.
var formats = new[] { "M.d.yyyy", "dd.MM.yyyy" };
var dateValue = DateTime.ParseExact(
dateString, formats, new CultureInfo("sl-SI"), DateTimeStyles.None);
You can actually try all date formats in every possible pattern, then use ParseExact to format the value you want
public string GetDateFormat(string input)
{
string[] formats = {"M/d/yyyy", "MM/dd/yyyy",
"d/M/yyyy", "dd/MM/yyyy",
"yyyy/M/d", "yyyy/MM/dd",
"M-d-yyyy", "MM-dd-yyyy",
"d-M-yyyy", "dd-MM-yyyy",
"yyyy-M-d", "yyyy-MM-dd",
"M.d.yyyy", "MM.dd.yyyy",
"d.M.yyyy", "dd.MM.yyyy",
"yyyy.M.d", "yyyy.MM.dd",
"M,d,yyyy", "MM,dd,yyyy",
"d,M,yyyy", "dd,MM,yyyy",
"yyyy,M,d", "yyyy,MM,dd",
"M d yyyy", "MM dd yyyy",
"d M yyyy", "dd MM yyyy",
"yyyy M d", "yyyy MM dd",
"d-MMM-yyyy", "d/MMM/yyyy", "d MMM yyyy", "d.MMM.yyyy",
"d-MMM-y", "d/MMM/y", "d MMM y", "d.MMM.y",
"dd-MMM-yyyy", "dd/MMM/yyyy", "dd MMM yyyy", "dd.MMM.yyyy",
"MMM/dd/yyyy", "MMM-dd-yyyy", "MMM dd yyyy", "MMM.dd.yyyy", "MMM.dd.yyyy"
};
DateTime dateValue;
foreach (string dateStringFormat in formats)
{
if (DateTime.TryParseExact(input, dateStringFormat,
CultureInfo.InvariantCulture,
DateTimeStyles.None,
out dateValue))
{
Console.WriteLine(dateStringFormat);
return dateStringFormat;
}
}
return null;
}

Categories