DateTime TryParseExact and padding - c#

I'm calling TryParse on a string that I want to parse as a DateTime. Simple stuff. And it all works when the format is as I'd expect. But when each component/some of the components of the date are a single figure, the parse fails.
Example:
var dateFormat = "yyyy-dd-MM hh:mm:ss";
var dateString = "2006-4-1 2:3:5";
DateTime.TryParseExact(dateString, dateFormat,
CultureInfo.InvariantCulture, DateTimeStyles.None, out result)
If I change my dateString to "2006-04-01 02:03:05", it parses fine.
Question
How can I tell the parser to interpret 2 as 02 so that the above parses successfully?
What I've Tried
Manually padding each part of the date time to ensure it fits the format. This works, but it doesn't feel very elegant. Is this the only way?
I've also tried, with no success, to use a format like m instead of mm.

Just use
// please note single letters (d, M, h, m, s) whenever you allow single digits
var dateFormat = "yyyy-d-M h:m:s";
And you'll get it:
var dateString = "2006-4-1 2:3:5";
DateTime.TryParseExact(dateString, dateFormat,
CultureInfo.InvariantCulture, DateTimeStyles.None, out result)

With regular expression:
int[] n = new Regex("[^0-9]+").Split("2006-4-1 2:3:5").Select(int.Parse).ToArray();
var datetime = new DateTime(n[0], n[1], n[2], n[3], n[4], n[5]);

Related

C# parse DateTime String to time only

I am new to C# and I have a string like "2021-06-14 19:27:14:979". Now I want to have only the time "19:27:14:979". So do I parse the string to a specific DateTime format and then convert it back to a string or would you parse or cut the string itself?
It is important that I keep the 24h format. I don't want AM or PM.
I haven't found any solution yet. I tried to convert it to DateTime like:
var Time1 = DateTime.ParseExact(time, "yyyy-MM-dd HH:mm:ss:fff");
var Time2 = Time1.ToString("hh:mm:ss:fff");
But then I lost the 24h format.
Your code is almost working, but ParseExact needs two additional arguments and ToString needs upper-case HH for 24h format:
var Time1 = DateTime.ParseExact("2021-06-14 19:27:14:979", "yyyy-MM-dd HH:mm:ss:fff", null, DateTimeStyles.None);
var Time2 = Time1.ToString("HH:mm:ss:fff");
Read: https://learn.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings#uppercase-hour-h-format-specifier
Instead of passing null as format provider(means current culture) you might want to pass a specifc CultureInfo, for example CultureInfo.CreateSpecificCulture("en-US").
You can just split it at the blank and take the last part like this
var timestamp = "2021-06-14 19:27:14:979";
var timePart = timestamp.Split(' ')[1];
in your case that seems easier than parsing into a DateTime and back into a string.

Dateformat is right but getting String was not recognized as a valid DateTime

My dateformat is dd/MM/yyyy.
I have a date column in my file with values like 1/08/2019 to 31/08/2019.
But I'm getting the following error when processing that file:
System.FormatException: String was not recognized as a valid DateTime.
at System.DateTimeParse.ParseExact(String s, String format, DateTimeFormatInfo dtfi, DateTimeStyles style)
You've specified in your format string that the days and months must be double digits, but it appears that your input can be single digits.
In order to solve this, you need to specify a single digit in the format string by using a single d for the day portion (and a single M for the month, too).
It's also safe to use a single digit in the format string, since it will handle both single and double digits.
So your format string should look like: "d/M/yyyy"
For example, these all work:
var a = DateTime.ParseExact("1/8/2019", "d/M/yyyy", CultureInfo.CurrentCulture);
var b = DateTime.ParseExact("1/08/2019", "d/M/yyyy", CultureInfo.CurrentCulture);
var c = DateTime.ParseExact("01/8/2019", "d/M/yyyy", CultureInfo.CurrentCulture);
var d = DateTime.ParseExact("01/08/2019", "d/M/yyyy", CultureInfo.CurrentCulture);
difficult to say as you show the error but not the actual code, as you have dates in your file of differennt format, like d/MM/yyyy and dd/MM/yyyy try to use TryParse instead of ParseExact and if the TryParse fails with one format ( d/MM/yyyy ), then do another TryParse with the second format ( dd/MM/yyyy ) that way you should be able to cover both cases.
Again, without seeing the code it is difficult to give more detailed feedback.
also you could use an approach with TryParseExact and multiple format strings, like shown here:
var formatStrings = new string[] { "MM/dd/yyyy hh:mm:ss tt", "yyyy-MM-dd hh:mm:ss" };
if (DateTime.TryParseExact(dt, formatStrings, enUS, DateTimeStyles.None, out dateValue))
return dateValue;
see this SO answer: https://stackoverflow.com/a/17859959/559144

c# split with some delimeters

I have a string like "1392/02/10 22:30:15", how can I separate each number in a variable with split? my code is in the following:
string str1="1392/02/10 22:30:15";
string[] str2 = str1.Split(new char[] { '/', ':',' '});
I got 1392, 02 and 10 but to get 22 by
int hour = int.Parse(str2[3]);
make an execption with this title:"Input string was not in a correct format."
I'd parse the date
string input = "1392/02/10 22:30:15";
string format = "yyyy'/'MM'/'dd HH:mm:ss";
DateTime result = DateTime.ParseExact(input, format, System.Globalization.CultureInfo.InvariantCulture);
int hour = result.Hour;
Fiddle: https://dotnetfiddle.net/489Ev3
It would make much more sense if you'd just parse the date as a DateTime:
string str1 = "1392/02/10 22:30:15";
DateTime d = DateTime.ParseExact(str1, "yyyy/MM/dd HH:mm:ss", CultureInfo.InvariantCulture);
If you are not sure about the validness of your input, you can use TryParseExact:
if (DateTime.TryParseExact(str1, "yyyy/MM/dd HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime d))
{
// the date is valid, use it
}
Your current code works, but is quite error prone. You better rely on pieces of the framework that automate this task. One problem with your code could be an extra space, a tab instead of a space, etc.

Converting string to valid DateTime

I know there are allot of questions regarding this, but I've been trying all day to get this conversion to work and have had no luck when applying the answers to the same question posted here. Every time I try to Parse the string to a DateTime, I get a "String was not recognized as a valid DateTime" exception. If I use Convert.ToDateTime, I can get a Date back from my string, but I need the hh:ss as well.
Here is my simplified code that is ruining my day:
var test = "2015-05-08T05:00Z";
DateTime testTime = new DateTime();
//testTime = Convert.ToDateTime(test);
testTime = DateTime.ParseExact(test, "mm/DD/yyyy HH:ss",
System.Globalization.CultureInfo.InvariantCulture);
Console.WriteLine(testTime);
Why is this string not recognized as a valid DateTime when trying to convert?
All help is appreciated
Try this...
var test = "2015-05-08T05:00Z";
DateTime testTime = new DateTime();
testTime = DateTime.Parse(test, null, System.Globalization.DateTimeStyles.RoundtripKind);
Console.WriteLine(testTime);
Console.ReadLine();
Or even with DateTime.ParseExact()
var test = "2015-05-08T05:00Z";
DateTime testTime = new DateTime();
testTime = DateTime.ParseExact(test, "yyyy-MM-ddTHH:ssZ", System.Globalization.CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind);
Console.WriteLine(testTime);
Console.ReadLine();
Results:
The format string you are using ("mm/DD/yyyy HH:ss") doesn't match your input in any way.
Have you looked at the DateTime.ParseExact documentation? You could try something like this:
testTime = DateTime.ParseExact(test, "yyyy-MM-ddTHH:ssZ",
System.Globalization.CultureInfo.InvariantCulture,
System.Globalization.DateTimeStyles.AssumeUniversal);
A couple of notes:
There is no point in setting testTime = new DateTime() if you are going to parse it on the next line. Just drop that line entirely and use var testTime = DateTime.ParseExact(...);
Are you sure that HH:ss is what you want? That seems like a very strange way to write a time. HH:mm or mm:ss would make more sense.
You should fix your expected pattern and take the time zone into account.
If your need a DateTime of DateTimeKind.Local:
var date = DateTime.ParseExact("2015-05-08T05:00Z", "yyyy-MM-dd'T'HH:mm'Z'",
CultureInfo.InvariantCulture);
If your need a DateTime of DateTimeKind.Utc:
var date = DateTime.ParseExact("2015-05-08T05:00Z", "yyyy-MM-dd'T'HH:mm'Z'",
CultureInfo.InvariantCulture,
DateTimeStyles.AssumeUniversal
| DateTimeStyles.AdjustToUniversal);
You are doing an exact parse, which means that the parse format string must match exactly with your date literal string. But your parse format string in ParseExact
uses / instead of - in the test literal string.
has a space instead of the T in the test literal string
does not match Z at the end of your test literal string.
Further it is not in yyyy-MM-dd order of your test literal string.
#Shar1er80' s solution is nice and frees you from having to specify a correct parse format string for ParseExact. I'd recommend going with that.
However, if you want to use ParseExact, you need to do this:
testTime = DateTime.ParseExact(test, "yyyy-MM-ddTHH:ssZ",
System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.AdjustToUniversal);
Note that I added a DateTimeStyle of AdjustToUniversal to ensure that your time is interpreted as UTC. The Z in the parse format string is just there to consume a Z. See https://stackoverflow.com/a/833143/49251 for more info on the issue of Z not actually being a part of the format string per se.

Parse string to DateTime in C#

I have date and time in a string formatted like that one:
"2011-03-21 13:26" //year-month-day hour:minute
How can I parse it to System.DateTime?
I want to use functions like DateTime.Parse() or DateTime.ParseExact() if possible, to be able to specify the format of the date manually.
DateTime.Parse() will try figure out the format of the given date, and it usually does a good job. If you can guarantee dates will always be in a given format then you can use ParseExact():
string s = "2011-03-21 13:26";
DateTime dt =
DateTime.ParseExact(s, "yyyy-MM-dd HH:mm", CultureInfo.InvariantCulture);
(But note that it is usually safer to use one of the TryParse methods in case a date is not in the expected format)
Make sure to check Custom Date and Time Format Strings when constructing format string, especially pay attention to number of letters and case (i.e. "MM" and "mm" mean very different things).
Another useful resource for C# format strings is String Formatting in C#
As I am explaining later, I would always favor the TryParse and TryParseExact methods. Because they are a bit bulky to use, I have written an extension method which makes parsing much easier:
var dtStr = "2011-03-21 13:26";
DateTime? dt = dtStr.ToDate("yyyy-MM-dd HH:mm");
Or more simply, if you want to use the date patterns of your current culture implicitly, you can use it like:
DateTime? dt = dtStr.ToDate();
In that case no specific pattern need to be specified.
Unlike Parse, ParseExact etc. it does not throw an exception, and allows you to check via
if (dt.HasValue) { // continue processing } else { // do error handling }
whether the conversion was successful (in this case dt has a value you can access via dt.Value) or not (in this case, it is null).
That even allows to use elegant shortcuts like the "Elvis"-operator ?., for example:
int? year = dtStr?.ToDate("yyyy-MM-dd HH:mm")?.Year;
Here you can also use year.HasValue to check if the conversion succeeded, and if it did not succeed then year will contain null, otherwise the year portion of the date. There is no exception thrown if the conversion failed.
Solution:  The   .ToDate()   extension method
Try it in .NetFiddle
public static class Extensions
{
/// Extension method parsing a date string to a DateTime? <para/>
/// <summary>
/// </summary>
/// <param name="dateTimeStr">The date string to parse</param>
/// <param name="dateFmt">dateFmt is optional and allows to pass
/// a parsing pattern array or one or more patterns passed
/// as string parameters</param>
/// <returns>Parsed DateTime or null</returns>
public static DateTime? ToDate(this string dateTimeStr, params string[] dateFmt)
{
// example: var dt = "2011-03-21 13:26".ToDate(new string[]{"yyyy-MM-dd HH:mm",
// "M/d/yyyy h:mm:ss tt"});
// or simpler:
// var dt = "2011-03-21 13:26".ToDate("yyyy-MM-dd HH:mm", "M/d/yyyy h:mm:ss tt");
const DateTimeStyles style = DateTimeStyles.AllowWhiteSpaces;
if (dateFmt == null)
{
var dateInfo = System.Threading.Thread.CurrentThread.CurrentCulture.DateTimeFormat;
dateFmt=dateInfo.GetAllDateTimePatterns();
}
var result = DateTime.TryParseExact(dateTimeStr, dateFmt, CultureInfo.InvariantCulture,
style, out var dt) ? dt : null as DateTime?;
return result;
}
}
Some information about the code
You might wonder, why I have used InvariantCulture calling TryParseExact: This is to force the function to treat format patterns always the same way (otherwise for example "." could be interpreted as decimal separator in English while it is a group separator or a date separator in German). Recall we have already queried the culture based format strings a few lines before so that is okay here.
Update: .ToDate() (without parameters) now defaults to all common date/time patterns of the thread's current culture.
Note that we need the result and dt together, because TryParseExact does not allow to use DateTime?, which we intend to return.
In C# Version 7 you could simplify the ToDate function a bit as follows:
// in C#7 only: "DateTime dt;" - no longer required, declare implicitly
if (DateTime.TryParseExact(dateTimeStr, dateFmt,
CultureInfo.InvariantCulture, style, out var dt)) result = dt;
or, if you like it even shorter:
// in C#7 only: Declaration of result as a "one-liner" ;-)
var result = DateTime.TryParseExact(dateTimeStr, dateFmt, CultureInfo.InvariantCulture,
style, out var dt) ? dt : null as DateTime?;
in which case you don't need the two declarations DateTime? result = null; and DateTime dt; at all - you can do it in one line of code.
(It would also be allowed to write out DateTime dt instead of out var dt if you prefer that).
The old style of C# would have required it the following way (I removed that from the code above):
// DateTime? result = null;
// DateTime dt;
// if (DateTime.TryParseExact(dateTimeStr, dateFmt,
// CultureInfo.InvariantCulture, style, out dt)) result = dt;
I have simplified the code further by using the params keyword: Now you don't need the 2nd overloaded method any more.
Example of usage
var dtStr="2011-03-21 13:26";
var dt=dtStr.ToDate("yyyy-MM-dd HH:mm");
if (dt.HasValue)
{
Console.WriteLine("Successful!");
// ... dt.Value now contains the converted DateTime ...
}
else
{
Console.WriteLine("Invalid date format!");
}
As you can see, this example just queries dt.HasValue to see if the conversion was successful or not. As an extra bonus, TryParseExact allows to specify strict DateTimeStyles so you know exactly whether a proper date/time string has been passed or not.
More Examples of usage
The overloaded function allows you to pass an array of valid formats used for parsing/converting dates as shown here as well (TryParseExact directly supports this), e.g.
string[] dateFmt = {"M/d/yyyy h:mm:ss tt", "M/d/yyyy h:mm tt",
"MM/dd/yyyy hh:mm:ss", "M/d/yyyy h:mm:ss",
"M/d/yyyy hh:mm tt", "M/d/yyyy hh tt",
"M/d/yyyy h:mm", "M/d/yyyy h:mm",
"MM/dd/yyyy hh:mm", "M/dd/yyyy hh:mm"};
var dtStr="5/1/2009 6:32 PM";
var dt=dtStr.ToDate(dateFmt);
If you have only a few template patterns, you can also write:
var dateStr = "2011-03-21 13:26";
var dt = dateStr.ToDate("yyyy-MM-dd HH:mm", "M/d/yyyy h:mm:ss tt");
Advanced examples
You can use the ?? operator to default to a fail-safe format, e.g.
var dtStr = "2017-12-30 11:37:00";
var dt = (dtStr.ToDate()) ?? dtStr.ToDate("yyyy-MM-dd HH:mm:ss");
In this case, the .ToDate() would use common local culture date formats, and if all these failed, it would try to use the ISO standard format "yyyy-MM-dd HH:mm:ss" as a fallback. This way, the extension function allows to "chain" different fallback formats easily.
You can even use the extension in LINQ, try this out (it's in the .NetFiddle above):
var strDateArray = new[] { "15-01-2019", "15.01.2021" };
var patterns=new[] { "dd-MM-yyyy", "dd.MM.yyyy" };
var dtRange = strDateArray.Select(s => s.ToDate(patterns));
dtRange.Dump();
which will convert the dates in the array on the fly by using the patterns and dump them to the console.
Some background about TryParseExact
Finally, Here are some comments about the background (i.e. the reason why I have written it this way):
I am preferring TryParseExact in this extension method, because you avoid exception handling - you can read in Eric Lippert's article about exceptions why you should use TryParse rather than Parse, I quote him about that topic:2)
This unfortunate design decision1) [annotation: to
let the Parse method throw an exception] was so vexing that of course
the frameworks team implemented TryParse shortly thereafter which does the right thing.
It does, but TryParse and TryParseExact both are still a lot less than comfortable to use: They force you to use an uninitialized variable as an out parameter which must not be nullable and while you're converting you need to evaluate the boolean return value - either you have to use an ifstatement immediately or you have to store the return value in an additional boolean variable so you're able to do the check later. And you can't just use the target variable without knowing if the conversion was successful or not.
In most cases you just want to know whether the conversion was successful or not (and of course the value if it was successful), so a nullable target variable which keeps all the information would be desirable and much more elegant - because the entire information is just stored in one place: That is consistent and easy to use, and much less error-prone.
The extension method I have written does exactly that (it also shows you what kind of code you would have to write every time if you're not going to use it).
I believe the benefit of .ToDate(strDateFormat) is that it looks simple and clean - as simple as the original DateTime.Parse was supposed to be - but with the ability to check if the conversion was successful, and without throwing exceptions.
1) What is meant here is that exception handling (i.e. a try { ... } catch(Exception ex) { ...} block) - which is necessary when you're using Parse because it will throw an exception if an invalid string is parsed - is not only unnecessary in this case but also annoying, and complicating your code. TryParse avoids all this as the code sample I've provided is showing.
2) Eric Lippert is a famous StackOverflow fellow and was working at Microsoft as principal developer on the C# compiler team for a couple of years.
var dateStr = #"2011-03-21 13:26";
var dateTime = DateTime.ParseExact(dateStr, "yyyy-MM-dd HH:mm", CultureInfo.CurrentCulture);
Check out this link for other format strings!
DateTime.Parse() should work fine for that string format. Reference:
http://msdn.microsoft.com/en-us/library/1k1skd40.aspx#Y1240
Is it throwing a FormatException for you?
Put the value of a human-readable string into a .NET DateTime with code like this:
DateTime.ParseExact("April 16, 2011 4:27 pm", "MMMM d, yyyy h:mm tt", null);
You can also use XmlConvert.ToDateString
var dateStr = "2011-03-21 13:26";
var parsedDate = XmlConvert.ToDateTime(dateStr, "yyyy-MM-dd hh:mm");
It is good to specify the date kind, the code is:
var anotherParsedDate = DateTime.ParseExact(dateStr, "yyyy-MM-dd hh:mm", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
More details on different parsing options http://amir-shenodua.blogspot.ie/2017/06/datetime-parsing-in-net.html
The simple and straightforward answer -->
using System;
namespace DemoApp.App
{
public class TestClassDate
{
public static DateTime GetDate(string string_date)
{
DateTime dateValue;
if (DateTime.TryParse(string_date, out dateValue))
Console.WriteLine("Converted '{0}' to {1}.", string_date, dateValue);
else
Console.WriteLine("Unable to convert '{0}' to a date.", string_date);
return dateValue;
}
public static void Main()
{
string inString = "05/01/2009 06:32:00";
GetDate(inString);
}
}
}
/**
* Output:
* Converted '05/01/2009 06:32:00' to 5/1/2009 6:32:00 AM.
* */
Try the following code
Month = Date = DateTime.Now.Month.ToString();
Year = DateTime.Now.Year.ToString();
ViewBag.Today = System.Globalization.CultureInfo.InvariantCulture.DateTimeFormat.GetMonthName(Int32.Parse(Month)) + Year;
DateTime.ParseExact(DateTime, Format, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AllowLeadingWhite | DateTimeStyles.AllowTrailingWhite)
for example:
DateTime.ParseExact("2011-03-21 13:26", "yyyy-MM-dd hh:mm", DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AllowLeadingWhite | DateTimeStyles.AllowTrailingWhite);

Categories