Why does this attempt to parse DateTime fail? - c#

This:
bool ret = DateTime.TryParse("Sunday 11 November", out date);
fails to parse the date string? Why?
I realize the string is an incomplete date, but why can't the framework handle it? Does the framework always try to return a legitimate date? Because if so, that would explain it (Sunday 11th November 2014 is not a valid date)

It's easy enough to verify, just change the date to a valid one (Sunday 9 November), and guess what, it works. You will also see that the year is set to 2014.
So yes, it appears that if the date is not valid, parsing will fail.

In the documentation for DateTime.TryParse, it states the following:
This method tries to ignore unrecognized data, if possible, and fills
in missing month, day, and year information with the current date.
In your example, the year is missing, so it will plug in the current year, giving Sunday 11 November 2014. I'm assuming it is invalid because the 11th of Nov does not fall on a Sunday. The documentation does include examples that include the name of the day.
It's funny to see this question, because this non-intuitive feature of TryParse (filling in missing parts) bit someone in my office just today.

Related

How do I parse iso8601-2004 datetimes into datetime following current iso8601 standard [duplicate]

I noticed quite an interesting error when parsing some times.
DateTime fails to parse 24:00:00. Under some Googling and Stacking, I found out that DateTime only recognizes 00 - 23 (what the?????), so if your input is 24:00:00, you're out of luck. You would think someone would put in a condition to equate 24:00:00 as 00:00:00 (the midnight), but not yet..
My question is, how do I allow DateTime to allow me to parse 24:00:00?
Unfortunately I cannot to use NodaTime under specification reasons (sorry Jon. I love your library though).
Experimentation below:
An input of 2014-03-18 24:00:00 would present the following error. Expected.
An input of 2014-03-18 23:59:59 would successfully parse. Expected.
An input of 2014-03-19 00:00:00` would successfully parse. Expected.
There is no "24th hour" support in the DateTime class.
The hour (HH/H, 24-hour clock) must be 0-23, inclusive. This is why 00:00:00 is valid, but 24:00:00 is not.
Change 24:00:00 to 00:00:00 (before parsing) and, if needed, advance the day as appropriate (after parsing).
The following will work on times in the provided format (but only up to the 24th hour) although it doesn't account for an arbitrary format. Supporting different format strings only adds additional complications.
DateTime ParseWithTwentyFourthHourToNextDay (string input) {
var wrapped = Regex.Replace(input, #"24:(\d\d:\d\d)$", "00:$1");
var res = DateTime.ParseExact(wrapped, "yyyy-MM-dd HH:mm:ss", null);
return wrapped != input
? res.AddDays(1)
: res;
}
24:00:00 doesn't exist. It is 00:00:00 - 23:59:59
Why would you like to parse 24:00:00 as a valid time expression when it would be like saying 09:05:60. The roof for time is 23:59:59.99999999999 and after that, it turns over to 00:00:00.
Before parsing, do a simple search and replace - replace '24:00:00' with '00:00:00' and then parse as usual.
Convert to Minute.
if t.TotalMinutes < 0
double _24h = 0;
_24h = 1440 + t.TotalMinutes;
TimeSpan t = TimeSpan.FromMinutes(_24h);

Why does DateTime.TryParse see "1,5" as valid (and how to prevent)? [duplicate]

This question already has answers here:
DateTime.TryParse successfully parsing some numeric numbers
(5 answers)
Closed 1 year ago.
While trying to validate user input, an input string of "1,5" results in a valid date:
var s = "1,5";
DateTime d;
var b = DateTime.TryParse(s,
CultureInfo.InvariantCulture,
DateTimeStyles.None,
out d);
Console.WriteLine("s: " + s);
Console.WriteLine("b: " + b);
Console.WriteLine("d: " + d);
Output is:
s: 1,5
b: True
d: 1/5/2021 12:00:00 AM
.NET Fiddle
My intention was that "1,5" is not considered as a valid DateTime. Obviously, I'm wrong.
I've tried this both in .NET Framework 4.8 and .NET Core 5 with same results.
Having looked through the .NET sources of the DateTime.TryParse method, I still cannot figure out why this is considered a valid date.
In addition I would love to somehow prevent the method to recognize this as a valid date. My guess is to go with DateTime.TryParseExact but maybe there are better options.
My questions
Why does DateTime.TryParse in invariant culture consider "1,5" as a valid date.
How to prevent this behavior?
It's parsing it as "Month, Day" in the current year - that's why it allows it.
DateTime.TryParse() is notoriously permissive - the advice is generally to use DayTime.TryParseExact() to avoid such things (as you suggest yourself).
There's no better way to solve this than using DateTime.TryParseExact().
This behaviour is actually documented:
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
So it parses the month and day number, and then sets the year to the current date's year and the time to midnight.

How does DateTime.TryParse know the date format?

Here is a scenario.
You have a string that represents a date i.e. "Jan 25 2016 10:10 AM".
You want to know whether it represents a date in a specific culture.
You want to know what dateTime pattern satisfies this date string.
Example:
Date string is "Jan 25 2016 10:10 AM"
Culture is en-US
The POSSIBLE format for it could be "MMM dd yyyy HH:mm tt"
Implementation:
To get the list of all dateTime patterns you can get a CultureInfo.DateTimeFormat.GetAllDateTimePatterns()
Then try the overloaded version of DateTime.TryParseExact(dateString, pattern, culture, DateTimeStyles.None, out resultingDate) for each of the patterns above and see whether it can parse a date.
That should give you the needed dateTime pattern.
HOWEVER if we iterate all those patterns it will not find any matches!
This is even more weird if you try and use a DateTime.TryParse(dateString, culture, DateTimeStyles.None, out resultingDate) and it DOES parse the correct date!
So the question is how come the DateTime.TryParse knows the pattern of a date string when this info is not a part of CultureInfo and how to get to this info in a culture?
Thanks!
I agree with xanatos, there is no perfect solution for that and you can't assume that every format GetAllDateTimePatterns returns can be perfectly parsable with Parse or TryParse methods.
From DateTimeFormatInfo.GetAllDateTimePatterns;
You can use the custom format strings in the array returned by the
GetAllDateTimePatterns method in formatting operations. However, if
you do, the string representation of a date and time value returned in
that formatting operation cannot always be parsed successfully by the
Parse and TryParse methods. Therefore, you cannot assume that the
custom format strings returned by the GetAllDateTimePatterns method
can be used to round-trip date and time values.
If you see Remarks section on the page, there are only 42 formats that can be parsed by TryParse method in 96 formats that GetAllDateTimePatterns method returns for it-IT culture for example.7
Tarek Mahmoud Sayed responded as;
Parse/TryParse are implemented as finite state machine so it doesn’t
really use the date patterns in parsing. It just split the parsed
string into tokens and try to find if the token match specific part of
the date (like Month, day, day of week…etc.). in the other hand
ParseExact/TryParseExact will just parse the string according to the
passed format pattern.
In short, Parsing is really hard because there are a lot of things that can trip it up. And someone in some government could suddenly decide that country X should use D/M/Y instead of M/D/Y, or could have someone entering data used to the other format.
I talk a little about this on a blog post (toward the bottom-ish) https://web.archive.org/web/20190110065542/https://blogs.msdn.microsoft.com/shawnste/2005/04/05/culture-data-shouldnt-be-considered-stable-except-for-invariant/
DateTime.Parse attempts to guess what the input might be based on the pattern(s) and separators it sees in the specified culture. Unfortunately, some cultures are REALLY hard to guess at. For example, . has been used for time formats in some locales, so is 1.1.1 12.12.12 the 12th day of December 2012? Or the 1st day of January 2001?
ParseExact (as the other answers suggest) is more reliable as you can tell it exactly what you're looking for - even better, you can also tell the user exactly what to enter. (Hopefully this is human input). Unfortunately it requires the user to follow the template.
This is also why most date controls you encounter, especially on the web, have separate fields for month, day & year.
For machine readable formats its best to spit it out in some standard format and read it back in with that exact same format. We've had customers send data from one country to another using the CurrentCulture and wonder why their vendor can't read it ;-)

Is there a way to determine if Convert.ToDateTime added the year?

I have a large collection of text files that need to be parsed using Regexes. Some of the data that I'm collecting are dates that come in all sorts of formats, such as 12/1/15, Dec 1, 2015, 12-1-15, etc. They sometimes have a year listed and sometimes don't. My problem occurs when I have dates that span two years, i.e. 12/1 - 1/8, where the first date needs the year 2015 and the second date needs the year 2016. Currently I'm parsing them as strings and trying to convert them to DateTimes. This adds the current day's year, so if it's parsed in 2015, the second date is wrong and if it's parsed in 2016 the first date is wrong. Is there a way to determine when Convert.ToDateTime adds the year since the string was missing one? If I could determine this I have a way to determine which year needs to be added.
Convert.ToDateTime just uses DateTime.Parse. My understanding is that when interpreting MM/dd formats, it will always assume the current year.
In your scenario, it sounds like you will need to make some determination on how you want to handle this. For instance, you could test that if the latter date precedes the prior date, you add a year.

String not recognized as a valid DateTime because the day of week was incorrect

I'm getting this STRING value from a code written in the UK
"15:11 PM Friday, February 20, 2"
and try to convert it to a DateTime using Convert.ToDateTime("string value")
I get an Exception stating that
String was not recognized as a valid DateTime because the day of week was incorrect.
The 20th was a Friday on February 2015.
Is the problem the fact that we are missing the YEAR?
The documentation
The return value is the result of invoking the DateTime.Parse method on value using the formatting information in a DateTimeFormatInfo object that is initialized for the current culture.
Look at the formats in there and you'll very likely not find one without the year specified. Add your own to it or parse it with a format directly.
Technically the error message is correct - the day of the week is incorrect if you are dealing with the year 2.
The UK uses dates just like the rest of the civilised world (I exclude the USA and any other country that uses mm/dd/yy from the set of "civilised"), so I would be checking why you are missing the rest of the year.

Categories