DateTime sync in Myy format

I need to parse a DateTime in "Myy" format, therefore:

  • the first day is a month without a leading zero (from 1 to 12) and
  • the second is the year with two digits.

Examples:

115 -> January 2015 1016 -> October 2016 

When using DateTime.ParseExact with "Myy" as the format, DateTime throws an exception if the month does not have a null value.

This code throws an exception:

 var date = DateTime.ParseExact("115", "Myy", CultureInfo.InvariantCulture); // throws FormatException 

So far, this works great:

 var date = DateTime.ParseExact("1016", "Myy", CultureInfo.InvariantCulture); // works fine 

The MSDN documentation clearly defines format specifiers:

  • "M" is a month, from 1 to 12.
  • "MM" is a month, from 01 to 12.
  • "yy" is the year, from 00 to 99.

Is there any format that would allow the case described above, i.e. "Myy" time format, in which month without leading zeros?

EDIT

Just for the sake of accuracy: we are talking about using the format in ParseExact, and not about how to analyze it ourselves using string manipulations.

+7
c # datetime parsing
source share
3 answers

This is because the DateTime parser reads from left to right without returning.

As he tries to read the month, he begins to take the first two digits and uses it to analyze the month. And then he tries to make out the year, but only one figure remains, so he fails. There is simply no way to solve this problem without introducing a separator character:

 DateTime.ParseExact("1 15", "M yy", CultureInfo.InvariantCulture) 

If you cannot do this, first read on the right and separate the year separately (using string manipulations). Or just add zero to the beginning and MMyy it as MMyy :

 string s = "115"; if (s.Length < 4) s = "0" + s; Console.WriteLine(DateTime.ParseExact(s, "MMyy", CultureInfo.InvariantCulture)); 

Research!

Since ispiro is requested for sources: parsing is done with the DateTimeParse type. For us, this 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 the comment is there when digitLen is 1 . Be aware that the first number in this other ParseDigits overload is minDigitLen and the other is maxDigitLen . Thus, basically for the last digitLen of 1 function will also take a maximum length of 2 (which allows you to use one M to correspond to two-digit months).

Now another overload that actually does the job contains this loop:

 while (tokenLength < maxDigitLen) { if (!str.GetNextDigit()) { str.Index--; break; } result = result * 10 + str.GetDigit(); tokenLength++; } 

As you can see, the method continues to take more digits from the string until it exceeds the maximum length. The rest of the method is just error checking and stuff.

Finally, let's take a look at the actual parsing in DoStrictParse . There we have the following cycle :

 // 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 happens over the characters in the format string, and then tries to match the string from left to right using this format. ParseByFormat performs additional logic that captures repeating formats (for example, yy instead of just y )) and uses this information to fork into different formats. For our months, this is the corresponding 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, we close the circle to ParseDigits , which is transmitted with a token length of 1 for one M But, as we saw above, it will still correspond to two numbers, if possible; and all that without checking whether the number of two digits that it matches matches for a month. Therefore, 130 will not match for January 2030. It will correspond to the 13th month and will not pass later.

+12
source share

From MSDN :

If the format is a custom format template that does not include a date or (for example, "yyyyMMdd HHmm"), use an invariant culture for the provider parameter and the widest form of each custom format specifier. For example, if you want to specify the clock in the template format, specify a wider form, "HH", instead of a narrower form, "H".

In other words, it probably cannot be resolved the way you want.

+1
source share

Too easy??

  string date = "115"; if (date.Count()==3) { date = "0" + date; } 
0
source share

All Articles