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?
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.
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.
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.
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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With