DateTime.TryParse cannot parse DateTime.MinValue - c#

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?

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;
}

Related

C# with mongodb DateTime Convert

I want to convert "ISODate(\"2014-11-13T18:43:33.868Z\")" to c# datetime ex 2014-11-13 18:43:33.
Value "ISODate(\"2014-11-13T18:43:33.868Z\")" take from MongoDB collection.
Please Help.
You can set DateTime in C# to UTC
var createDate = DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Utc)
or
dateTime = DateTime.SpecifyKind(dateTime, DateTimeKind.Utc)
Then insert type DateTime into mongodb
It worked in my case.
You can store your date as a BsonDateTime object when you pull it from the database, then convert it as follows:
DateTime dt = bdt.ToUniversalTime();
And you may find this question useful to learn more about how ToUniversalTime() works.
If I understand clearly, just because it writes ISODate in your string, that doesn't make it ISO 8601 format. The "O" or "o" standard format specifier complies ISO 8601 format and which is "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffffffK" custom format string for a DateTime. That doesn't match with your string format.
If your all strings has a stable format like this, you can use custom date and time formats with literal string delimiter like;
string s = "ISODate(\"2014-11-13T18:43:33.868Z\")";
string format = "'ISODate(\"'yyyy-MM-dd'T'HH:mm:ss.fff'Z\")'";
DateTime date;
if(DateTime.TryParseExact(s, format, CultureInfo.InvariantCulture,
DateTimeStyles.None, out date))
{
Console.WriteLine (date);
}
If you want to string representation of your DateTime with "2014-11-13 18:43:33" format, you can use DateTime.ToString() method like;
date.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture);

Parsing "mm/dd/yy" string to "mm/dd/yyyy" date object in C#

I am working on an ASP.NET Mvc application with C# and facing a problem when I try to upload a .CSV file in order to save its data to database.
The problem comes from the date column of the .CSV file. There are two formats of date used in that column. The first one is "mm/dd/yyyy" that I have no problem to parse to a DateTime object by the following code:
// for the date : 09/30/2014
DateTime tempo = Convert.ToDateTime("09/30/2014");
The second format is "mm/dd/yy". The same method above doesn't work for this format and throws an exception
// for the date : 09/30/14
DateTime tempo = Convert.ToDateTime("09/30/14");
// this line throws ;
// [09/30/14] String was not recognized as a valid DateTime. exception
Is there a solution which works for both of date formats ?
Thanks for your help.
First, mm specifier is for minutes, MM specifier is for months. Convert.ToDateTime method uses your CurrentCulture by default. That means MM/dd/yy is not a standard date and time format your CurrentCulture but MM/dd/yyyy is.
You can use custom date and time formatting string like;
string s = "09/30/14";
DateTime date;
if(DateTime.TryParseExact(s, "MM/dd/yy", CultureInfo.InvariantCulture,
DateTimeStyles.None, out date))
{
// Successfully parse
}
Be aware "/" custom format specifier has a special meaning of replace me with the current culture or supplied culture date separator. That means even if your string and format matches, you parsing will fail.
Is there a solution which works for both of date formats ?
DateTime.TryParseExact method has an overload that takes formats as a string array. If your string matches one of your formats, it will returns true.
string s = "09/30/14";
sstring[] formats = {"MM/dd/yy", "MM/dd/yyyy"};
DateTime date;
if(DateTime.TryParseExact(s, formats, CultureInfo.InvariantCulture,
DateTimeStyles.None, out date))
{
// Successfully parse
}
Also you can see all standard date and time patters of your CurrentCulture like;
foreach (var format in CultureInfo.CurrentCulture.
DateTimeFormat.
GetAllDateTimePatterns())
{
Console.WriteLine (format);
}

Console application string was not recognised as valid datetime

I have a excel sheet in which am taking a date column in this format "23/8/11 01:33:01:PM"
and am inserting it in sql 2008 using datarow but am getting a error
String was not recognised as valid datetime.
Can any one please help?
DateTime newdate = Convert.ToDateTime(row[8].ToString());
Here how Convert.ToDateTime method looks like when you decompile it;
public static DateTime ToDateTime(string value)
{
if (value == null)
return new DateTime(0L);
else
return DateTime.Parse(value, (IFormatProvider) CultureInfo.CurrentCulture);
}
As you can see, this method use DateTime.Parse method with your CurrentCulture. And if your string doesn't match your current culture date format, your code will be broken. That's the reason you get this error.
Use DateTime.ParseExact with "dd/M/yy hh:mm:ss:tt" format instead.
Converts the specified string representation of a date and time to its
DateTime equivalent. The format of the string representation must
match a specified format exactly or an exception is thrown.
string s = "23/8/11 01:33:01:PM";
DateTime newdate = DateTime.ParseExact(s, "dd/M/yy hh:mm:ss:tt", CultureInfo.InvariantCulture);
Console.WriteLine(newdate);
Output will be;
8/23/2011 1:33:01 PM
Here a DEMO.
For your case;
DateTime newdate = DateTime.ParseExact(row[8].ToString(), "dd/M/yy hh:mm:ss:tt", CultureInfo.InvariantCulture);
For more informations, take a look;
Custom Date and Time Format Strings
Convert.ToDateTime internally calls DateTime.Parse which by default will use the current culture of your application. If 23/8/11 01:33:01:PM is not a valid format for this culture then this method will fail.
For specific date formats it's best to use DateTime.ParseExact e.g.
DateTime.ParseExact("23/8/11 01:33:01:PM", "dd/M/yy hh:mm:ss:tt", CultureInfo.InvariantCulture);
This approach makes your code culture independent which means the date will always be parsed correctly (given it's in the specified format).
This will work:
DateTime newdate = Convert.ToDateTime("8/23/11 01:33:01 PM");
I changed day and month and removed the colon a the end. But that is very specific. You need to know more about the dates passed to do that.

C# Datetime format conversion

I have a conversion problem with datetime. I have a date string as MM/dd/yyyy. Now I need to convert it to yyyy-MM-dd.
But I'm facing some error. Please help
public static DateTime ToDBDateTime(string _dateTime)
{
string sysFormat = "MM/dd/yyyy hh:mm:ss tt";
string _convertedDate = string.Empty;
if (_dateTime != null || _dateTime != string.Empty)
{
_convertedDate = DateTime.ParseExact(_dateTime, sysFormat, System.Globalization.CultureInfo.InvariantCulture).ToString(_toDBDateFormat);
//_convertedDate = Convert.ToDateTime(_dateTime).ToString(_toDBDateFormat);
/// Debug.Print(sysFormat);
}
return Convert.ToDateTime(_convertedDate);
}
And I want to know that is there is any way to pass the datetime in various formats and it would return the expected format.
E.g.: if I pass date as dd/MM/yyyy or MM/dd/yyyy, the above function would return the date in format as yyyy-MM-dd.
Please provide some suggestion to solve datetime issues.
I have a date string as MM/dd/yyyy
Right... and yet you're trying to parse it like this:
string sysFormat = "MM/dd/yyyy hh:mm:ss tt";
...
_convertedDate = DateTime.ParseExact(_dateTime, sysFormat,
CultureInfo.InvariantCulture)
You need to give a format string which matches your input - so why are you including a time part? You probably just want:
string sysFormat = "MM/dd/yyyy";
However, that's not the end of the problems. You're then converting that DateTime back into a string like this:
.ToString(_toDBDateFormat)
... and parsing it once more:
return Convert.ToDateTime(_convertedDate);
Why on earth would you want to do that? You should avoid string conversions as far as possible. Aside from anything else, what's to say that _toDBDateFormat (a variable name which raises my suspicions to start with) and Convert.ToDateTime (which always uses the current culture for parsing) are going to be compatible?
You should:
Work out how you want to handle being given an empty string or null, and just return an appropriate DateTime then
Otherwise, just parse using the right format.
This part of your question also concerns me:
E.g.: if I pass date as dd/MM/yyyy or MM/dd/yyyy, the above function would return the date in format as yyyy-MM-dd.
There's no such thing as "the date in format as yyyy-MM-dd". A DateTime is just a date and time value. It has no intrinsic format. You specify how you want to format it when you format it. However, if you're using the value for a database query, you shouldn't be converting it into a string again anyway - you should be using parameterized SQL, and just providing it as a DateTime.
As you have a date in a string with the format "MM/dd/yyyy" and want to convert it to "yyyy-MM-dd" you could do like this:
DateTime dt = DateTime.ParseExact(dateString, "MM/dd/yyyy", CultureInfo.InvariantCulture);
dt.ToString("yyyy-MM-dd");
Use the inbuilt tostring like this:
Convert.ToDateTime(_convertedDate).ToString("MM/dd/yyyy") or whatever format you want.
I tried this and its working fine.
DateTime date1 = new DateTime(2009, 8, 1);
date1.ToString("yyyy-MM-dd hh:mm:ss tt");
You can apply any format in this ToString.
Hope that helps
Milind

Get DateTime Obj from "mm/yyyy" format Date string

I have a date string in format "08/1999" I want to get the first date of the corresponding month. eg : in this case 08/01/1999.
It is simple for en-Us culture. I break the string, append "01" in the string to get 08/01/1999 and then DateTime.Parse(datestring) but this is valid for en-US culture only.
How can I do this for different culture ?
My datestring will always be in mm/yyyy format. and I am trying to obtain a DataTime obj from this dateString.
Use ParseExact method. Note upper-cased M's are for months and lower-cased m's for minutes.
string dateToConvert = "08/1999";
string format = "MM/yyyy";
CultureInfo provider = CultureInfo.InvariantCulture;
DateTime result = DateTime.ParseExact(dateToConvert, format, provider);
Output:
{1999-08-01 00:00:00}
You can also use Convert.ToDateTime and Parse methods. It will produce the same result, but in implicite way:
DateTime result = Convert.ToDateTime(dateToConvert, provider); // Output: {1999-08-01 00:00:00}
DateTime result = DateTime.Parse(dateToConvert, provider); // Output: {1999-08-01 00:00:00}
Read more at:
Parsing Date and Time Strings
Standard Date and Time Format Strings
Custom Date and Time Format Strings
I'm not sure if I understand your question correctly, but you can try passing CultureInfo.InvariantCulture if you want to force the US date format regardless of the regional settings of the client computer:
DateTime.Parse("08/1999", System.Globalization.CultureInfo.InvariantCulture)
I break the string, append "01" in the string to get 08/01/1999 and then DateTime.Parse(datestring)
That's a very long-winded way to do it. Simply this will work:
DateTime.Parse("08/1999")
How can I do this for different culture ?
If your string is always in this format, do this:
DateTime.Parse("08/1999", CultureInfo.InvariantCulture)

Categories