How to Convert Stringified Date Value in format Month/Day/Year Time as a DateTime?

I've got a class that contains two DateTime members.

When I try to assign a "human-readable" value representing a date to the DateTime member, though, it rejects it with the message, "String was not recognized as a valid DateTime."

The line of code that fails is:

md.BeginDate = DateTime.Parse(reader.GetValue(5).ToString());

In context, showing the value that I am trying to convert from a string representation of a DateTime:

enter image description here

Based on the 1st and accepted answer here [https://stackoverflow.com/questions/2193012/string-was-not-recognized-as-a-valid-datetime-format-dd-mm-yyyy], I also tried this:

md.BeginDate = DateTime.ParseExact(reader.GetValue(6).ToString(), "MM/dd/yyyy", null); 

...but with the same ignominious result.

UPDATE

Based on this, I tried the following:

CultureInfo provider = CultureInfo.InvariantCulture;
string format = "yyyy-MM-dd HH:mm:ss.ffffff";
. . .
DateTime.ParseExact(dateString, format, provider);

...but get the same result.

The value of "dateValAsStr" is 2021-01-21 11:25:56.9608384

UPDATE 2

It turns out it was a really dumb oversight on my part. When I stepped through it, I saw that the Date (TEXT) value in the database was empty. So this code "works" (doesn't throw an exception):

CultureInfo provider = CultureInfo.InvariantCulture;
string format = "yyyy-MM-dd HH:mm:ss.fffffff";
. . .
string qry = "SELECT LocationName, Address1, City, StateOrSo, PostalCode, " +
                        "BeginDate, EndDate, MapDetailNotes, Latitude, Longitude " +
                        "FROM CartographerDetail " +
                        "WHERE FKMapName = @FKMapName";
. . .
dateValAsStr = reader.GetValue(5).ToString().Trim();
if (! String.IsNullOrWhiteSpace(dateValAsStr))
{
    md.BeginDate = DateTime.ParseExact(dateValAsStr, format, provider).Date;
}
dateValAsStr = reader.GetValue(6).ToString().Trim();
if (!String.IsNullOrWhiteSpace(dateValAsStr))
{
    md.EndDate = DateTime.ParseExact(dateValAsStr, format, provider).Date;
}

Upvotes: 5

Views: 2058

Answers (4)

codebender
codebender

Reputation: 489

I'd use Parse instead. There's a pretty good series of examples in the Microsoft Documentation

(string dtStr, string descr)[]  dateInfo = { 
      ("08/18/2018 07:22:16", "String with a date and time component"),
      ("08/18/2018", "String with a date component only"),
      ("8/2018", "String with a month and year component only"),
      ("8/18", "String with a month and day component only"),
      ("07:22:16", "String with a time component only"),
      ("7 PM", "String with an hour and AM/PM designator only"),
      ("2018-08-18T07:22:16.0000000Z", "UTC string that conforms to ISO 8601"),
      ("2018-08-18T07:22:16.0000000-07:00", "Non-UTC string that conforms to ISO 8601"),
      ("Sat, 18 Aug 2018 07:22:16 GMT", "String that conforms to RFC 1123"),
      ("08/18/2018 07:22:16 -5:00", "String with date, time, and time zone information" ) };

Console.WriteLine($"Today is {DateTime.Now:d}\n");

foreach (var i in dateInfo) {
  Console.WriteLine($"'{i.dtStr}' = {DateTime.Parse(i.dtStr)} {i.descr+ ":",-52}");
}

Upvotes: 1

Maytham Fahmi
Maytham Fahmi

Reputation: 33437

If you have time where the Millisecond size has inconsistent length, try this method that I use to one system we have that deliver such inconsistent time.

public static string DynamicMillisecondDateTimeFormat(string date)
{
    var size = date[(date.LastIndexOf(".", StringComparison.Ordinal) + 1)..].Length;
    var fs = new string('f', size);
    return size == 19 ? "yyyy-MM-dd HH:mm:ss" : $"yyyy-MM-dd HH:mm:ss.{fs}";
}

To test this lets do following:

string[] dates = {
    "2021-01-21 11:25:56",
    "2021-01-21 11:25:56.9",
    "2021-01-21 11:25:56.96",
    "2021-01-21 11:25:56.960",
    "2021-01-21 11:25:56.9608",
    "2021-01-21 11:25:56.96083",
    "2021-01-21 11:25:56.960838",
    "2021-01-21 11:25:56.9608384"
};

var provider = CultureInfo.InvariantCulture;

foreach (var date in dates)
{
    var format = DynamicMillisecondDateTimeFormat(date);
    DateTime.TryParseExact(date, format, provider, DateTimeStyles.None, out var dateTime);
    Console.WriteLine(dateTime.ToString(format));
}

If we take that in your context, you can do some thing like:

var format = DynamicMillisecondDateTimeFormat(ReaderOptions.GetValue(5).ToString());
bool parsable = DateTime.TryParseExact(date, format, provider, DateTimeStyles.None, out var dateTime);
if (parsable)
{
    md.BeginDate = date;
}

Btw this link has some interesting information about the date time formatting.

In addition thanks to @MattJohnson-Pint commented and made me aware of better alternative to my DynamicMillisecondDateTimeFormat method where you just need to do following format, it will automatically take all millisecond lengths between 0 to 7. note it should have capital Fs:

"yyyy-MM-dd HH:mm:ss.FFFFFFF"

Upvotes: 3

Haverka
Haverka

Reputation: 38

You can just create a new DateTime like this, by splitting the reader.GetValue(5) into the appropriate slot

int d1 = 200;
int d2 = 2;
int d3 = 24;
DateTime datet = new DateTime(d1,d2,d3);
md.BeginDate = datet;

The d1, d2, and d3 is what you will need to replace with the data split from getvalue

Upvotes: 1

Enigmativity
Enigmativity

Reputation: 117175

The simple example you give is this:

string dateString = "2021-01-21 11:25:56.9608384";
CultureInfo provider = CultureInfo.InvariantCulture;
string format = "yyyy-MM-dd HH:mm:ss.fffffff";
DateTime result = DateTime.ParseExact(dateString, format, provider);

Note that the number of decimal places for the seconds is 7, yet your format only has 6 fs.

If you change to 7 fs then it works fine.

Upvotes: 4

Related Questions