Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DateTime.TryParse cannot parse DateTime.MinValue

I'm using a library called Json.NET that uses the following code internally to parse a JSON string into a DateTime:

if (DateTime.TryParse(s, Culture, DateTimeStyles.RoundtripKind, out dt))
{
     dt = DateTimeUtils.EnsureDateTime(dt, DateTimeZoneHandling);
     SetToken(JsonToken.Date, dt);
     return dt;
}

I thought Json.NET was screwing up the conversion, but it looks like it's DateTime.TryParse itself that's botching the value.

When I parse the following valid Iso date (which corresponds to UTC DateTime.MinValue):

string json = "0001-01-01T00:00:00+00:00";
DateTime dt;
DateTime.TryParse(json, invariantCulture, DateTimeStyles.RoundtripKind, out dt);

The result is a localized DateTime: {0001-01-01 8:00:00 PM}, which when converted back to Utc time gives {0001-01-02 0:00:00 PM}. Essentially, the date underflowed, which is exactly the kind of problem you would expect DateTimeStyles.RoundtripKind to avoid.

How do I avoid this scenario?

like image 814
Alain Avatar asked Feb 07 '14 20:02

Alain


People also ask

How to use TryParse in c# for date?

TryParse(String, IFormatProvider, DateTimeStyles, DateTime) Converts the specified string representation of a date and time to its DateTime equivalent using the specified culture-specific format information and formatting style, and returns a value that indicates whether the conversion succeeded.

How do I use DateTime TryParse in Uipath?

TryParse Method (System) Converts the specified string representation of a date and time to its DateTime equivalent and returns a value that indicates whether the conversion succeeded. @opas1216 - you can use the regular expression to validate the date… you can use below expression to verify/validate the date string.

What is the value of DateTime MinValue in C#?

The value of this constant is equivalent to 00:00:00.0000000 UTC, January 1, 0001, in the Gregorian calendar. MinValue defines the date and time that is assigned to an uninitialized DateTime variable.


1 Answers

Why use DateTimeStyles.RoundtripKind? The documentation for RoundtripKind says:

The DateTimeKind field of a date is preserved when a DateTime object is converted to a string using the "o" or "r" standard format specifier, and the string is then converted back to a DateTime object.

The string output from the "o" or "r" standard format specifiers are not like the ISO 8601 string you are trying to parse. It doesn't sound to me like RoundtripKind is really supposed to work with any date time string format. It sounds like the round trip is for the DateTime.Kind property when the string is in a particular format.

Since you know the format of the string you are trying to parse, then I would suggest using DateTime.TryParseExact.

I have had to support a couple different versions of the ISO 8601 string - either of these formats are valid date-time values in ISO 8601 (and there are even more options for dates, times and fractional seconds, but I didn't those):

0001-01-01T00:00:00+00:00

0001-01-01T00:00:00Z

Here's a method that will handle either of these formats:

private bool TryParseIso8601(string s, out DateTime result)
{
    if (!string.IsNullOrEmpty(s))
    {
        string format = s.EndsWith("Z") ? "yyyy-MM-ddTHH:mm:ssZ" : "yyyy-MM-ddTHH:mm:sszzz";
        return DateTime.TryParseExact(s, format, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal, out result);
    }

    result = new DateTime(0L, DateTimeKind.Utc);
    return false;
}
like image 98
Doug Avatar answered Sep 22 '22 23:09

Doug