Evil Date Parsing lives! Viva Evil Date Parsing!, explained

Sorting it all Out
Michael Kaplan's random stuff of dubious value
Be sure to read the disclaimer here first!

Evil Date Parsing lives! Viva Evil Date Parsing!, explained

  • Comments 3

So it was yesterday in Evil Date Parsing lives! Viva Evil Date Parsing! that I pointed out the reported problem with the following code:

CultureInfo ci = new CultureInfo("ar-sa");
ci.DateTimeFormat.Calendar = ci.OptionalCalendars[1];
Thread.CurrentThread.CurrentCulture = ci;
String value = DateTime.UtcNow.ToString("u");
DateTime dt = DateTime.Parse(value, ci, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal);

Basically, that DateTime.Parse call was hitting an error.

No one really guessed what was going on, and apparently no one debugged the five lines of code to look for clues, either.

So I guess I'll explain it a bit now.

First I will provide a hint, in the form of an older blog of mine, Long term planning is not always done.

Now the calendar here is the System.Globalization.UmAlQuraCalendar.

If you look at the value of that value string, it is:

الجمعة, صفر 1431 08:10:08

which may give an additional hint.

Now the problem becomes clear, if you take the meaning of the two flags being passed to the Parse method:

  • AdjustToUniversal: Parses s and, if necessary, converts it to UTC. If s includes a time zone offset, or if s contains no time zone information but styles includes the DateTimeStyles.AssumeLocal flag, the method parses the string, calls ToUniversalTime to convert the returned DateTime value to UTC, and sets the Kind property to DateTimeKind.Utc. If s indicates that it represents UTC, or if s does not contain time zone information but styles includes the DateTimeStyles.AssumeUniversal flag, the method parses the string, performs no time zone conversion on the returned DateTime value, and sets the Kind property to DateTimeKind.Utc. In all other cases, the flag has no effect.
  • AssumeUniversal: Specifies that if s lacks any time zone information, it is assumed to represent UTC. Unless the DateTimeStyles.AdjustToUniversal flag is present, the method converts the returned DateTime value from UTC to local time and sets its Kind property to DateTimeKind.Local.

It is obviously fair to say that the date is the original "Hijri" style date in the 14th century, and trying to instruct the parser that it is a UTC date will cause it to fail since it is WAY out of range.

Now perhaps you could argue that there is a bug in the initial ToString("u") call in creating a string that it is the universal format but still using the other calendar's date and year. In fact I might tend to argue that at a minimum that is where the documentation problem exists, and maybe also the actual behavior problem....

Comment on the blather
Leave a Comment
  • Please add 6 and 4 and type the answer here:
  • Post
Blog - Comment List
  • I did the test but didn't have time to post. I got completely different results (on .NET4Beta2/Win7, if it matters):

    First difference of note: the UmAlQuraCalendar was OptionalCalendars[0]; [1] was the HijriCalendar. Second difference: ToString("u") returned 2010-etc-etc-etcZ - both actually in the universal sortable format (which what you pasted here was not) and with the Gregorian Year. Third, the HijriCalendar took that string, and read it as some date way in the future. Which brings us to my diagnosis of the exception: the blog post you linked

    [I wrote another comment, but I lost it due to clicking the back button or something, and don't _think_ I posted it - if by some chance you see two comments from me on this post, delete one.]

  • Nitpicker's corner: 1431 is in the 15th century, n'est pas?

  • So I was asked if I knew what the following comment from the site was about:..

Page 1 of 1 (3 items)