I'm having huge problems with solving this problem. I'm trying to parse a string using Datetime.ParseExact().
I have the following code:
DateTime.ParseExact("20151210 832", "yyyyMMdd Hmm", CultureInfo.InvariantCulture);
I get following error:
An unhandled exception of type 'System.FormatException' occurred in
mscorlib.dll Additional information: String was not recognized as a
valid DateTime.
What am I doing wrong? How can I solve this problem?
UPDATE:
I can also get times like this:
00:01 => 1
01:00 => 1
01:10 => 10
Since H specifier can be 2 digit, this method try to parse your 83 with H specifier. Since there is no such an hour, you get FormatException.
For your case, one way to prevent this is putting a leading zero just before your 8.
var s = "20151210 832";
var result = s.Split(' ')[0] + " 0" + s.Split(' ')[1];
var dt = DateTime.ParseExact(result, "yyyyMMdd Hmm", CultureInfo.InvariantCulture);
Be aware, this will not work for all cases. For example, if your hour part already two digit, if your single minute does not have leading zero.. etc.
Or you can put delimiter for your all parts but in such a case, you need to manipulate both your string and format.
.NET Team suggest this way as well.
Just insert a separator before minutes (for example, a whitespace) and then you can parse it like this:
string example = "20151210 832";
example = example.Insert(example.Length - 2, " ");
var dateTime = DateTime.ParseExact(example, "yyyyMMdd H mm", CultureInfo.InvariantCulture);
I assume that the datetime string always contains two digits specifying minutes (check an article about Custom Date and Time Format Strings). If my assumption is wrong then this string cannot be parsed.
Related
I have some c# code like this:
string myString = "20180426";
I know how to parse around specific characters (using the string.Split thing), but how do I get it to return 3 strings like this:
2018
04
26
I have several strings that are formatted this way ("YYYYMMDD"), so I don't want code that will only work for this specific string. I tried using
var finNum = myString[0] + myString[1] + myString[2] + myString[3];
Console.Write(finNum);
But I guess it's treating the characters as integers, rather than a text string because it's doing some mathematical operation with them instead of concatenating (it's not addition either because it's returning 203, which isn't the sum of 2, 0, 1 and 8).
I've tried changing var to string, but it won't let me implicitly convert int to string. Why does it think that string myString is an int, rather than a string, which is what I declared it as?
I could also use DateTime.Parse and DateTime.ParseExact, but apparently "20180426" isn't recognized as a valid DateTime:
DateTime myDate = DateTime.ParseExact(myString, "YYYYMMDD", null);
Console.WriteLine(myDate);
Thank you for your help. I know the answer is probably stupidly easy and I feel dumb for asking but I seriously checked all over various websites and can't find a solution that works for my issue here.
I could also use DateTime.Parse and DateTime.ParseExact, but
apparently "20180426" isn't recognized as a valid DateTime.
Yes, because the format string YYYYMMDD is incorrect, years and days are lowercase:
DateTime myDate = DateTime.ParseExact(myString, "yyyyMMdd", null);
If you want the year, month and day:
int year = myDate.Year;
int month = myDate.Month;
int day = myDate.Day;
If you want year, month and day separated by variables you could try:
string mystring = "20180426";
mystring = mystring.Insert(4,"-");
mystring = mystring.Insert(7,"-");
string year = mystring.Split('-')[0];
string month = mystring.Split('-')[1];
string day = mystring.Split('-')[2];
First I add a character "-" to separate year and month, then another to separate month and day. You get something like "2018-04-26"
Then I split the string and save the position 0 that store the first 4 numbers of your string into a variable named year.
Good luck!
I need to parse DateTime in "Myy" format, so:
the first number is a month without leading zero (1 to 12), and
the second number is a year with two digits.
Examples:
115 -> January 2015
1016 -> October 2016
When using DateTime.ParseExact with "Myy" as a format, DateTime throws an exception when month is without leading zero.
This code throws an exception:
var date = DateTime.ParseExact("115",
"Myy",
CultureInfo.InvariantCulture); // throws FormatException
While this works fine:
var date = DateTime.ParseExact("1016",
"Myy",
CultureInfo.InvariantCulture); // works fine
MSDN Documentation clearly defines format specifiers:
"M" – The month, from 1 through 12.
"MM" – The month, from 01 through 12.
"yy" – The year, from 00 to 99.
Is there any format which would resolve the above case, i.e. "Myy" date time format in which month is without leading zeros?
EDIT
Just to precise: The question is about using format in ParseExact specifically and not about how to parse it itself by using string manipulation.
This is because the DateTime parser reads from left to right without backtracking.
Since it tries to read a month, it starts taking the first two digits and uses it to parse the month. And then it tries to parse the year but there is only one digit left, so it fails. There is simply not a way to solve this without introducing a separation character:
DateTime.ParseExact("1 15", "M yy", CultureInfo.InvariantCulture)
If you can’t do that, read from the right first and split off the year separately (using string manipulation). Or just add a zero to the beginning and parse it as MMyy:
string s = "115";
if (s.Length < 4)
s = "0" + s;
Console.WriteLine(DateTime.ParseExact(s, "MMyy", CultureInfo.InvariantCulture));
Research!
Since ispiro asked for sources: The parsing is done by the DateTimeParse type. Relevant for us is the ParseDigits method:
internal static bool ParseDigits(ref __DTString str, int digitLen, out int result) {
if (digitLen == 1) {
// 1 really means 1 or 2 for this call
return ParseDigits(ref str, 1, 2, out result);
}
else {
return ParseDigits(ref str, digitLen, digitLen, out result);
}
}
Note that comment there in the case where digitLen equals 1. Know that the first number in that other ParseDigits overload is minDigitLen and the other is maxDigitLen. So basically, for a passed digitLen of 1, the function will also accept a maximum length of 2 (which makes it possible to use a single M to match the 2-digit months).
Now, the other overload that actually does the work contains this loop:
while (tokenLength < maxDigitLen) {
if (!str.GetNextDigit()) {
str.Index--;
break;
}
result = result * 10 + str.GetDigit();
tokenLength++;
}
As you can see, the method keeps taking more digits from the string until it exceeded the maximum digit length. The rest of the method is just error checking and stuff.
Finally, let’s look at the actual parsing in DoStrictParse. There, we have the following loop:
// Scan every character in format and match the pattern in str.
while (format.GetNext()) {
// We trim inner spaces here, so that we will not eat trailing spaces when
// AllowTrailingWhite is not used.
if (parseInfo.fAllowInnerWhite) {
str.SkipWhiteSpaces();
}
if (!ParseByFormat(ref str, ref format, ref parseInfo, dtfi, ref result)) {
return (false);
}
}
So basically, this loops over the characters in the format string, then tries to match the string from left to right using that format. ParseByFormat does additional logic that captures repeated formats (like yy instead of just y) and uses that information to branch into different formats. For our months, this is the relevant part:
if (tokenLen <= 2) {
if (!ParseDigits(ref str, tokenLen, out tempMonth)) {
if (!parseInfo.fCustomNumberParser ||
!parseInfo.parseNumberDelegate(ref str, tokenLen, out tempMonth)) {
result.SetFailure(ParseFailureKind.Format, "Format_BadDateTime", null);
return (false);
}
}
}
So here we close the circle to the ParseDigits which is passed with a token length of 1 for a single M. But as we’ve seen above, it will still match two digits if it can; and all that without validating whether the two digit number it matches makes any sense for a month. So 130 wouldn’t match for January 2030 either. It would match as the 13th month and fail there later.
From MSDN:
If format is a custom format pattern that does not include date or
time separators (such as "yyyyMMdd HHmm"), use the invariant culture
for the provider parameter and the widest form of each custom format
specifier. For example, if you want to specify hours in the format
pattern, specify the wider form, "HH", instead of the narrower form,
"H".
In other words, it's likely that it can't be solved the way you want.
Too simple??
string date = "115";
if (date.Count()==3)
{
date = "0" + date;
}
I am trying to format date entered by user.
Dates are provided in the following format:
d/M/yyyy (ie: 1/1/2012, but could be also 12/1/2012 or 1/12/2012)
however I need them converted to:
dd/MM/yyyy (ie: 01/01/2012)
I managed to do it in non-Regex way, like this:
string date = "1/1/2012";
if (date.IndexOf("/") == 1)
{
date = "0" + date;
}
if (date.Substring(4, 1) == "/")
{
date = date.Insert(3, "0");
}
I would really like to know how to do it with Regex.Replace, however, as it would probably be neater.
I tired different variations of the below:
string date = "1/1/2012"
date = Regex.Replace(date, #"\d{1}/", "0$&");
The above will work, but if the date is 12/1/2012, it will also make 102 out of 12. If I add ^ at the beginning of pattern I don't get the second number changed. I also tried combinations with [^|/] at the beginning, but also no luck. So at the moment it is either or.
Use word boundary \b which matches between a word character and a non-word character.
date = Regex.Replace(date, #"\b\d/", "0$&");
OR
date = Regex.Replace(date, #"\b(\d)/", "0$1/");
DEMO
If you're sure of the incoming format, I'd use DateTime.ParseExact instead, then use .ToString() to reformat the date:
DateTime dt = DateTime.ParseExact(input, "d/M/yyyy", CultureInfo.CurrentCulture);
string reformatted = dt.ToString("dd/MM/yyyy");
I'm having a bit of a issue with this.
What I want to do is take this string 27.0 and convert it to a timespan.
I tried every way I could think of in order to get it to work.
TimeSpan.Parse("27.0") I know it's a format issue but I'm not sure of the format to use.
I basically have 4 values
27.0
52.4
1:24.4
1:43.3
Is there a easy way to handle all these formats?
Thanks!
Sorry these are all seconds except the 1 is minute so 1 minute 24 seconds 4 milliseconds
You can use two different approaches. Use one of the TimeSpan.From...() methods. Those convert numbers to a TimeSpan. For example to convert the double 27 to a TimeSpan with 27 seconds you use
var ts = TimeSpan.FromSeconds(27)
The only problem you will face here is that it does not allow you to specify a string. So you could for example first parse your string as an double. If you do it naivly just like that, it can be you get what you wanted, or not.
var ts = TimeSpan.FromSeconds(double.Parse("27.0"))
But if you run this for example on a system with a German locale you will get a TimeSpan with 4 minutes and 30 seconds. The reason for that is that a dot in German is not a divider for a number, it is the thousand seperator. So that number is parsed as "270". So to be safe you should also provide a NumberFormat. A better way would be.
var culture = new CultureInfo("en-US");
var tsc = TimeSpan.FromSeconds(double.Parse("27.0", culture.NumberFormat));
Now you get your 27 seconds. But the problem is still that it only parses your two first strings correctly. Your other 3 strings will still not parse, because you can't convert them to numbers. But I still added this, to be aware of culture difference if you just go up and try to parse a number to an double und use TimeSpan.FromSeconds() and so on.
Now lets look further how you can parse every string. There exists TimeSpan.Parse() and TimeSpan.ParseExact().
Now you still must knew that TimeSpan.Parse() uses culture specific formatting. In a country where a time is not separated with colons a TimeSpan.Parse() will fail. On Top of that, TimeSpan assumes a format "hh:mm" at minimum. But the Colon in this format is culture-sensitive. You could use the "en-US" Culture once again, but it wouldn't solve the problem because he doesn't accept the format "27.0".
That is the reason why you must use the TimeSpan.ParseExact() method and and provide the formats that this method should be able to parse. It also allows you to specify formats that he should be able to parse. You now should end with something like this.
var culture = new CultureInfo("en-US");
var formats = new string[] {
#"s\.f",
#"ss\.f",
#"ss\.ff",
#"m\:ss\.f",
#"m\:ss\.ff",
#"mm\:ss\.ff"
};
foreach ( var str in new string[] { "27.0", "52.4", "1:24.4", "1:43.3" } ) {
var ts = TimeSpan.ParseExact(str, formats, culture.NumberFormat);
Console.WriteLine(ts.ToString());
}
Note that in this example I added a backslash to escape the dot and the colon. If you don't do this then the formatter itself treats this as a culture-sensitive separator. But what you want is exactly the colon or the dot.
The output of this code will be
00:00:27
00:00:52.4000000
00:01:24.4000000
00:01:43.3000000
try something like this:
var timeString = "1:24.4";
var timeComponents = timeString.Split(':', '.').Reverse().ToList();
var milliseconds = timeComponents.Any() ? int.Parse(timeComponents[0]) : 0;
var seconds = timeComponents.Count() > 1 ? int.Parse(timeComponents[1]) : 0;
var minutes = timeComponents.Count() > 2 ? int.Parse(timeComponents[2]) : 0;
var timeSpan = new TimeSpan(0, 0, minutes, seconds, milliseconds);
this will deal with the milliseconds literally. You may want to pad the string component of the milliseconds with '0's, as pointed out in the comments.
I have date/time format, for example:
"1-Mar-13 92230"
According to this document and this link the format is as follows:
"d-MMM-yy Hmmss", because:
Day is single digit, 1-30
Month is 3 letter abbreviation, Jan/Mar etc.
Year is 2 digits, eg 12/13
Hour is single digit for 24 hour clock, eg 9, 13 etc. (no 09)
Minute is standard (eg 01, 52)
Second is standard (eg 30, 02)
I'm trying to run the following code in my program, but I keep getting an error of "String was not recognized as a valid DateTime."
string input = "1-Mar-13 92330";
var date = DateTime.ParseExact(input, "d-MMM-yy Hmmss",
System.Globalization.CultureInfo.CurrentCulture);
Please help, I'm not too familiar with DateTime conversions, but I can't see where I've gone wrong here. Thanks!
UPDATE: Is this because time cannot be parsed without colons in between? (eg 1-Mar-13 9:22:30 gets parsed, but i have an external data source that would be impossible to rewrite from Hmmss to H:mm:ss)
You could fix your date:
var parts = "1-Mar-13 92230".Split(' ');
if (parts[1].Length == 5)
{
parts[1] = "0" + parts[1];
}
var newDate = parts[0] + " " + parts[1];
var date = DateTime.ParseExact(newDate, "d-MMM-yy HHmmss", System.Globalization.CultureInfo.CurrentCulture);
From msdn:
If format is a custom format pattern that does not include date or
time separators (such as "yyyyMMdd HHmm"), use the invariant culture
for the provider parameter and the widest form of each custom format
specifier. For example, if you want to specify hours in the format
pattern, specify the wider form, "HH", instead of the narrower form,
"H".
so you can try:
string input = "1-Mar-13 92330";
var date = DateTime.ParseExact(input, "d-MMM-yy Hmmss",
System.Globalization.CultureInfo.InvariantCulture);
Your input string has to be of following format
string input = "1-Mar-13 092330";
If you go back to your link, it says
H 24-hour clock hour (e.g. 19)
Now H is 24 hours, it should be represented with leading 0. If not imagine how would you handle the case of hours greater than 9 i.e which are in double digit.
If not your hour and Minute and Seconds has to be separated.
string input = "1-Mar-13 9 2330";
var date = DateTime.ParseExact(input, "d-MMM-yy H mmss",
System.Globalization.CultureInfo.InvariantCulture);
Your hour min and seconds need to be separated, as they are not getting distinguished.
string input = "1-Mar-13 9 23 30";
var date = DateTime.ParseExact(input, "d-MMM-yy H mm ss", System.Globalization.CultureInfo.CurrentCulture);