Collapse AsSpan().Slice(...) into .AsSpan(...) (dotnet/corefx#27867)
[platform/upstream/coreclr.git] / src / mscorlib / shared / System / Globalization / DateTimeParse.cs
index 2b0f41a..970d176 100644 (file)
@@ -17,10 +17,10 @@ namespace System
 
         internal static MatchNumberDelegate m_hebrewNumberParser = new MatchNumberDelegate(DateTimeParse.MatchHebrewDigits);
 
-        internal static DateTime ParseExact(ReadOnlySpan<char> s, String format, DateTimeFormatInfo dtfi, DateTimeStyles style)
+        internal static DateTime ParseExact(ReadOnlySpan<char> s, ReadOnlySpan<char> format, DateTimeFormatInfo dtfi, DateTimeStyles style)
         {
             DateTimeResult result = new DateTimeResult();       // The buffer to store the parsing result.
-            result.Init();
+            result.Init(s);
             if (TryParseExact(s, format, dtfi, style, ref result))
             {
                 return result.parsedDate;
@@ -31,11 +31,11 @@ namespace System
             }
         }
 
-        internal static DateTime ParseExact(ReadOnlySpan<char> s, String format, DateTimeFormatInfo dtfi, DateTimeStyles style, out TimeSpan offset)
+        internal static DateTime ParseExact(ReadOnlySpan<char> s, ReadOnlySpan<char> format, DateTimeFormatInfo dtfi, DateTimeStyles style, out TimeSpan offset)
         {
             DateTimeResult result = new DateTimeResult();       // The buffer to store the parsing result.
             offset = TimeSpan.Zero;
-            result.Init();
+            result.Init(s);
             result.flags |= ParseFlags.CaptureOffset;
             if (TryParseExact(s, format, dtfi, style, ref result))
             {
@@ -48,11 +48,11 @@ namespace System
             }
         }
 
-        internal static bool TryParseExact(ReadOnlySpan<char> s, String format, DateTimeFormatInfo dtfi, DateTimeStyles style, out DateTime result)
+        internal static bool TryParseExact(ReadOnlySpan<char> s, ReadOnlySpan<char> format, DateTimeFormatInfo dtfi, DateTimeStyles style, out DateTime result)
         {
             result = DateTime.MinValue;
             DateTimeResult resultData = new DateTimeResult();       // The buffer to store the parsing result.
-            resultData.Init();
+            resultData.Init(s);
             if (TryParseExact(s, format, dtfi, style, ref resultData))
             {
                 result = resultData.parsedDate;
@@ -61,12 +61,12 @@ namespace System
             return false;
         }
 
-        internal static bool TryParseExact(ReadOnlySpan<char> s, String format, DateTimeFormatInfo dtfi, DateTimeStyles style, out DateTime result, out TimeSpan offset)
+        internal static bool TryParseExact(ReadOnlySpan<char> s, ReadOnlySpan<char> format, DateTimeFormatInfo dtfi, DateTimeStyles style, out DateTime result, out TimeSpan offset)
         {
             result = DateTime.MinValue;
             offset = TimeSpan.Zero;
             DateTimeResult resultData = new DateTimeResult();       // The buffer to store the parsing result.
-            resultData.Init();
+            resultData.Init(s);
             resultData.flags |= ParseFlags.CaptureOffset;
             if (TryParseExact(s, format, dtfi, style, ref resultData))
             {
@@ -77,22 +77,17 @@ namespace System
             return false;
         }
 
-        internal static bool TryParseExact(ReadOnlySpan<char> s, String format, DateTimeFormatInfo dtfi, DateTimeStyles style, ref DateTimeResult result)
+        internal static bool TryParseExact(ReadOnlySpan<char> s, ReadOnlySpan<char> format, DateTimeFormatInfo dtfi, DateTimeStyles style, ref DateTimeResult result)
         {
-            if (format == null)
-            {
-                result.SetFailure(ParseFailureKind.ArgumentNull, nameof(SR.ArgumentNull_String), null, nameof(format));
-                return false;
-            }
             if (s.Length == 0)
             {
-                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                result.SetFailure(ParseFailureKind.FormatWithParameter, nameof(SR.Format_BadDateTime));
                 return false;
             }
 
             if (format.Length == 0)
             {
-                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadFormatSpecifier), null);
+                result.SetBadFormatSpecifierFailure();
                 return false;
             }
 
@@ -105,7 +100,7 @@ namespace System
                                                 DateTimeFormatInfo dtfi, DateTimeStyles style)
         {
             DateTimeResult result = new DateTimeResult();       // The buffer to store the parsing result.
-            result.Init();
+            result.Init(s);
             if (TryParseExactMultiple(s, formats, dtfi, style, ref result))
             {
                 return result.parsedDate;
@@ -122,7 +117,7 @@ namespace System
         {
             DateTimeResult result = new DateTimeResult();       // The buffer to store the parsing result.
             offset = TimeSpan.Zero;
-            result.Init();
+            result.Init(s);
             result.flags |= ParseFlags.CaptureOffset;
             if (TryParseExactMultiple(s, formats, dtfi, style, ref result))
             {
@@ -141,7 +136,7 @@ namespace System
             result = DateTime.MinValue;
             offset = TimeSpan.Zero;
             DateTimeResult resultData = new DateTimeResult();       // The buffer to store the parsing result.
-            resultData.Init();
+            resultData.Init(s);
             resultData.flags |= ParseFlags.CaptureOffset;
             if (TryParseExactMultiple(s, formats, dtfi, style, ref resultData))
             {
@@ -158,7 +153,7 @@ namespace System
         {
             result = DateTime.MinValue;
             DateTimeResult resultData = new DateTimeResult();       // The buffer to store the parsing result.
-            resultData.Init();
+            resultData.Init(s);
             if (TryParseExactMultiple(s, formats, dtfi, style, ref resultData))
             {
                 result = resultData.parsedDate;
@@ -178,13 +173,13 @@ namespace System
 
             if (s.Length == 0)
             {
-                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                result.SetFailure(ParseFailureKind.FormatWithParameter, nameof(SR.Format_BadDateTime));
                 return false;
             }
 
             if (formats.Length == 0)
             {
-                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadFormatSpecifier), null);
+                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_NoFormatSpecifier));
                 return false;
             }
 
@@ -198,13 +193,13 @@ namespace System
             {
                 if (formats[i] == null || formats[i].Length == 0)
                 {
-                    result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadFormatSpecifier), null);
+                    result.SetBadFormatSpecifierFailure();
                     return false;
                 }
                 // Create a new result each time to ensure the runs are independent. Carry through
                 // flags from the caller and return the result.
                 DateTimeResult innerResult = new DateTimeResult();       // The buffer to store the parsing result.
-                innerResult.Init();
+                innerResult.Init(s);
                 innerResult.flags = result.flags;
                 if (TryParseExact(s, formats[i], dtfi, style, ref innerResult))
                 {
@@ -213,7 +208,7 @@ namespace System
                     return (true);
                 }
             }
-            result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+            result.SetBadDateTimeFailure();
             return (false);
         }
 
@@ -336,7 +331,7 @@ namespace System
         //
         ////////////////////////////////////////////////////////////////////////////
 
-        //          End       NumEnd      NumAmPm     NumSpace    NumDaySep   NumTimesep  MonthEnd    MonthSpace  MonthDSep   NumDateSuff NumTimeSuff     DayOfWeek     YearSpace   YearDateSep YearEnd     TimeZone   Era         UTCTimeMark   
+        //          End       NumEnd      NumAmPm     NumSpace    NumDaySep   NumTimesep  MonthEnd    MonthSpace  MonthDSep   NumDateSuff NumTimeSuff     DayOfWeek     YearSpace   YearDateSep YearEnd     TimeZone   Era         UTCTimeMark
         private static DS[][] dateParsingStates = {
 // DS.BEGIN                                                                             // DS.BEGIN
 new DS[] { DS.BEGIN, DS.ERROR,   DS.TX_N,    DS.N,       DS.D_Nd,    DS.T_Nt,    DS.ERROR,   DS.D_M,     DS.D_M,     DS.D_S,     DS.T_S,         DS.BEGIN,     DS.D_Y,     DS.D_Y,     DS.ERROR,   DS.BEGIN,  DS.BEGIN,    DS.ERROR},
@@ -589,13 +584,13 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                     if ((result.flags & ParseFlags.TimeZoneUsed) != 0)
                     {
                         // Should not have two timezone offsets.
-                        result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                        result.SetBadDateTimeFailure();
                         return false;
                     }
                     result.flags |= ParseFlags.TimeZoneUsed;
                     if (!ParseTimeZone(ref str, ref result.timeZoneOffset))
                     {
-                        result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                        result.SetBadDateTimeFailure();
                         return false;
                     }
                 }
@@ -620,17 +615,9 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
             str.GetRegularToken(out tokenType, out tokenValue, dtfi);
 
 #if _LOGGING
-            // Builds with _LOGGING defined (x86dbg, amd64chk, etc) support tracing
-            // Set the following internal-only/unsupported environment variables to enable DateTime tracing to the console:
-            //
-            // COMPlus_LogEnable=1
-            // COMPlus_LogToConsole=1
-            // COMPlus_LogLevel=9
-            // COMPlus_ManagedLogFacility=0x00001000
             if (_tracingEnabled)
             {
-                BCLDebug.Trace("DATETIME", "[DATETIME] Lex({0})\tpos:{1}({2}), {3}, DS.{4}", Hex(str.Value),
-                               str.Index, Hex(str.m_current), tokenType, dps);
+                Trace($"Lex({Hex(str.Value)})\tpos:{str.Index}({Hex(str.m_current)}), {tokenType}, DS.{dps}");
             }
 #endif // _LOGGING
 
@@ -641,7 +628,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                 case TokenType.YearNumberToken:
                     if (raw.numCount == 3 || tokenValue == -1)
                     {
-                        result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                        result.SetBadDateTimeFailure();
                         LexTraceExit("0010", dps);
                         return false;
                     }
@@ -708,7 +695,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                                     }
                                     else
                                     {
-                                        result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                                        result.SetBadDateTimeFailure();
                                         LexTraceExit("0030 (TM.AM/TM.PM Happened more than 1x)", dps);
                                     }
                                     break;
@@ -721,12 +708,12 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                                 case TokenType.SEP_Time:
                                     if (!raw.hasSameDateAndTimeSeparators)
                                     {
-                                        result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                                        result.SetBadDateTimeFailure();
                                         LexTraceExit("0040 (Invalid separator after number)", dps);
                                         return false;
                                     }
 
-                                    // we have the date and time separators are same and getting a year number, then change the token to YearDateSep as 
+                                    // we have the date and time separators are same and getting a year number, then change the token to YearDateSep as
                                     // we are sure we are not parsing time.
                                     dtok.dtt = DTT.YearDateSep;
                                     break;
@@ -759,7 +746,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                                     break;
                                 default:
                                     // Invalid separator after number number.
-                                    result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                                    result.SetBadDateTimeFailure();
                                     LexTraceExit("0040 (Invalid separator after number)", dps);
                                     return false;
                             }
@@ -769,7 +756,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                             LexTraceExit("0050 (success)", dps);
                             return true;
                         }
-                        result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                        result.SetBadDateTimeFailure();
                         LexTraceExit("0060", dps);
                         return false;
                     }
@@ -792,7 +779,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                                 // Fix AM/PM parsing case, e.g. "1/10 5 AM"
                                 if (dps == DS.D_NN)
                                 {
-                                    if (!ProcessTerminaltState(DS.DX_NN, ref result, ref styles, ref raw, dtfi))
+                                    if (!ProcessTerminalState(DS.DX_NN, ref str, ref result, ref styles, ref raw, dtfi))
                                     {
                                         return false;
                                     }
@@ -802,7 +789,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                             }
                             else
                             {
-                                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                                result.SetBadDateTimeFailure();
                                 break;
                             }
                             if (dps == DS.T_NNt || dps == DS.T_Nt)
@@ -855,9 +842,9 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                             {
                                 dtok.num = dtfi.Calendar.ToFourDigitYear(tokenValue);
                             }
-                            catch (ArgumentOutOfRangeException e)
+                            catch (ArgumentOutOfRangeException)
                             {
-                                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), e);
+                                result.SetBadDateTimeFailure();
                                 LexTraceExit("0075 (Calendar.ToFourDigitYear failed)", dps);
                                 return false;
                             }
@@ -881,7 +868,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                             break;
                         default:
                             // Invalid separator after number number.
-                            result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                            result.SetBadDateTimeFailure();
                             LexTraceExit("0080", dps);
                             return false;
                     }
@@ -919,7 +906,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                                     goto default;
                                 default:
                                     // Invalid separator after number number.
-                                    result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                                    result.SetBadDateTimeFailure();
                                     LexTraceExit("0090", dps);
                                     return false;
                             }
@@ -927,7 +914,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                         else
                         {
                             // Invalid separator after number number.
-                            result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                            result.SetBadDateTimeFailure();
                             LexTraceExit("0100", dps);
                             return false;
                         }
@@ -968,7 +955,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                                 break;
                             default:
                                 // Invalid separator after number number.
-                                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                                result.SetBadDateTimeFailure();
                                 LexTraceExit("0110", dps);
                                 return false;
                         }
@@ -985,7 +972,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                     }
                     else
                     {
-                        result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                        result.SetBadDateTimeFailure();
                         LexTraceExit("0120 (DayOfWeek seen more than 1x)", dps);
                         return false;
                     }
@@ -1010,12 +997,12 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                             case TokenType.SEP_Time:
                                 if (!raw.hasSameDateAndTimeSeparators)
                                 {
-                                    result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                                    result.SetBadDateTimeFailure();
                                     LexTraceExit("0130 (Invalid separator after month name)", dps);
                                     return false;
                                 }
 
-                                // we have the date and time separators are same and getting a Month name, then change the token to MonthDatesep as 
+                                // we have the date and time separators are same and getting a Month name, then change the token to MonthDatesep as
                                 // we are sure we are not parsing time.
                                 dtok.dtt = DTT.MonthDatesep;
                                 break;
@@ -1036,7 +1023,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                                 break;
                             default:
                                 //Invalid separator after month name
-                                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                                result.SetBadDateTimeFailure();
                                 LexTraceExit("0130 (Invalid separator after month name)", dps);
                                 return false;
                         }
@@ -1044,7 +1031,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                     }
                     else
                     {
-                        result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                        result.SetBadDateTimeFailure();
                         LexTraceExit("0140 (MonthToken seen more than 1x)", dps);
                         return false;
                     }
@@ -1057,7 +1044,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                     }
                     else
                     {
-                        result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                        result.SetBadDateTimeFailure();
                         LexTraceExit("0150 (EraToken seen when result.era already set)", dps);
                         return false;
                     }
@@ -1073,7 +1060,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                     }
                     else
                     {
-                        result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                        result.SetBadDateTimeFailure();
                         LexTraceExit("0160 (JapaneseEraToken seen when result.era already set)", dps);
                         return false;
                     }
@@ -1088,7 +1075,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                     }
                     else
                     {
-                        result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                        result.SetBadDateTimeFailure();
                         LexTraceExit("0170 (TEraToken seen when result.era already set)", dps);
                         return false;
                     }
@@ -1102,7 +1089,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                     if ((result.flags & ParseFlags.TimeZoneUsed) != 0)
                     {
                         // Should not have two timezone offsets.
-                        result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                        result.SetBadDateTimeFailure();
                         LexTraceExit("0180 (seen GMT or Z more than 1x)", dps);
                         return false;
                     }
@@ -1126,7 +1113,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                     }
                     else
                     {
-                        result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                        result.SetBadDateTimeFailure();
                         LexTraceExit("0190 (AM/PM timeMark already set)", dps);
                         return false;
                     }
@@ -1134,7 +1121,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                 case TokenType.UnknownToken:
                     if (Char.IsLetter(str.m_current))
                     {
-                        result.SetFailure(ParseFailureKind.FormatWithParameter, nameof(SR.Format_UnknowDateTimeWord), str.Index);
+                        result.SetFailure(ParseFailureKind.FormatWithOriginalDateTimeAndParameter, nameof(SR.Format_UnknownDateTimeWord), str.Index);
                         LexTraceExit("0200", dps);
                         return (false);
                     }
@@ -1164,7 +1151,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                         return true;
                     }
 
-                    result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                    result.SetBadDateTimeFailure();
                     LexTraceExit("0240", dps);
                     return false;
             }
@@ -1213,7 +1200,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                     }
                     else if ((!Char.IsWhiteSpace(ch)))
                     {
-                        // Anthyhing other than whitespace outside hashes is invalid
+                        // Anything other than whitespace outside hashes is invalid
                         if (!foundStart || foundEnd)
                         {
                             return false;
@@ -1225,7 +1212,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                     // The has was un-paired
                     return false;
                 }
-                // Valid Hash usage: eat the hash and continue. 
+                // Valid Hash usage: eat the hash and continue.
                 str.GetNext();
                 return true;
             }
@@ -1557,7 +1544,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
             if ((result.flags & ParseFlags.HaveDate) != 0)
             {
                 // Multiple dates in the input string
-                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                result.SetBadDateTimeFailure();
                 return false;
             }
 
@@ -1590,7 +1577,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                     return true;
                 }
             }
-            result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+            result.SetBadDateTimeFailure();
             return false;
         }
 
@@ -1600,7 +1587,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
             if ((result.flags & ParseFlags.HaveDate) != 0)
             {
                 // Multiple dates in the input string
-                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                result.SetBadDateTimeFailure();
                 return false;
             }
 
@@ -1648,7 +1635,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                     return true;
                 }
             }
-            result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+            result.SetBadDateTimeFailure();
             return false;
         }
 
@@ -1657,7 +1644,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
             if ((result.flags & ParseFlags.HaveDate) != 0)
             {
                 // Multiple dates in the input string
-                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                result.SetBadDateTimeFailure();
                 return false;
             }
 
@@ -1692,7 +1679,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                     int year;
                     if (!TryAdjustYear(ref result, raw.GetNumber(0), out year) || !SetDateYMD(ref result, year, raw.month, 1))
                     {
-                        result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                        result.SetBadDateTimeFailure();
                         return false;
                     }
                     return true;
@@ -1702,7 +1689,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
             GetDefaultYear(ref result, ref styles);
             if (!SetDateYMD(ref result, result.Year, raw.month, raw.GetNumber(0)))
             {
-                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                result.SetBadDateTimeFailure();
                 return false;
             }
             return true;
@@ -1731,7 +1718,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                     return true;
                 }
             }
-            result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+            result.SetBadDateTimeFailure();
             return false;
         }
 
@@ -1740,7 +1727,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
             if ((result.flags & ParseFlags.HaveDate) != 0)
             {
                 // Multiple dates in the input string
-                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                result.SetBadDateTimeFailure();
                 return false;
             }
 
@@ -1775,7 +1762,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                     int year;
                     if (!TryAdjustYear(ref result, raw.GetNumber(0), out year) || !SetDateYMD(ref result, year, raw.month, 1))
                     {
-                        result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                        result.SetBadDateTimeFailure();
                         return false;
                     }
                     return true;
@@ -1785,7 +1772,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
             GetDefaultYear(ref result, ref styles);
             if (!SetDateYMD(ref result, result.Year, raw.month, raw.GetNumber(0)))
             {
-                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                result.SetBadDateTimeFailure();
                 return false;
             }
             return true;
@@ -1796,7 +1783,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
             if ((result.flags & ParseFlags.HaveDate) != 0)
             {
                 // Multiple dates in the input string
-                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                result.SetBadDateTimeFailure();
                 return false;
             }
 
@@ -1857,7 +1844,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                 }
             }
 
-            result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+            result.SetBadDateTimeFailure();
             return false;
         }
 
@@ -1866,7 +1853,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
             if ((result.flags & ParseFlags.HaveDate) != 0)
             {
                 // Multiple dates in the input string
-                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                result.SetBadDateTimeFailure();
                 return false;
             }
 
@@ -1892,7 +1879,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                     return true; // Year + MD
                 }
             }
-            result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+            result.SetBadDateTimeFailure();
             return false;
         }
 
@@ -1901,7 +1888,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
             if ((result.flags & ParseFlags.HaveDate) != 0)
             {
                 // Multiple dates in the input string
-                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                result.SetBadDateTimeFailure();
                 return false;
             }
 
@@ -1931,17 +1918,17 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                     return true; // DM + Year
                 }
             }
-            result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+            result.SetBadDateTimeFailure();
             return false;
         }
 
 
-        private static Boolean GetDayOfYMN(ref DateTimeResult result, ref DateTimeRawInfo raw, DateTimeFormatInfo dtfi)
+        private static Boolean GetDayOfYMN(ref DateTimeResult result, ref DateTimeRawInfo raw)
         {
             if ((result.flags & ParseFlags.HaveDate) != 0)
             {
                 // Multiple dates in the input string
-                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                result.SetBadDateTimeFailure();
                 return false;
             }
 
@@ -1950,16 +1937,16 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                 result.flags |= ParseFlags.HaveDate;
                 return true;
             }
-            result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+            result.SetBadDateTimeFailure();
             return false;
         }
 
-        private static Boolean GetDayOfYN(ref DateTimeResult result, ref DateTimeRawInfo raw, DateTimeFormatInfo dtfi)
+        private static Boolean GetDayOfYN(ref DateTimeResult result, ref DateTimeRawInfo raw)
         {
             if ((result.flags & ParseFlags.HaveDate) != 0)
             {
                 // Multiple dates in the input string
-                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                result.SetBadDateTimeFailure();
                 return false;
             }
 
@@ -1968,16 +1955,16 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                 result.flags |= ParseFlags.HaveDate;
                 return true;
             }
-            result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+            result.SetBadDateTimeFailure();
             return false;
         }
 
-        private static Boolean GetDayOfYM(ref DateTimeResult result, ref DateTimeRawInfo raw, DateTimeFormatInfo dtfi)
+        private static Boolean GetDayOfYM(ref DateTimeResult result, ref DateTimeRawInfo raw)
         {
             if ((result.flags & ParseFlags.HaveDate) != 0)
             {
                 // Multiple dates in the input string
-                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                result.SetBadDateTimeFailure();
                 return false;
             }
 
@@ -1986,7 +1973,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                 result.flags |= ParseFlags.HaveDate;
                 return true;
             }
-            result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+            result.SetBadDateTimeFailure();
             return false;
         }
 
@@ -2044,12 +2031,12 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
             return true;
         }
 
-        private static Boolean GetTimeOfN(DateTimeFormatInfo dtfi, ref DateTimeResult result, ref DateTimeRawInfo raw)
+        private static Boolean GetTimeOfN(ref DateTimeResult result, ref DateTimeRawInfo raw)
         {
             if ((result.flags & ParseFlags.HaveTime) != 0)
             {
                 // Multiple times in the input string
-                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                result.SetBadDateTimeFailure();
                 return false;
             }
             //
@@ -2057,7 +2044,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
             //
             if (raw.timeMark == TM.NotSet)
             {
-                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                result.SetBadDateTimeFailure();
                 return false;
             }
             result.Hour = raw.GetNumber(0);
@@ -2065,13 +2052,13 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
             return true;
         }
 
-        private static Boolean GetTimeOfNN(DateTimeFormatInfo dtfi, ref DateTimeResult result, ref DateTimeRawInfo raw)
+        private static Boolean GetTimeOfNN(ref DateTimeResult result, ref DateTimeRawInfo raw)
         {
             Debug.Assert(raw.numCount >= 2, "raw.numCount >= 2");
             if ((result.flags & ParseFlags.HaveTime) != 0)
             {
                 // Multiple times in the input string
-                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                result.SetBadDateTimeFailure();
                 return false;
             }
 
@@ -2081,12 +2068,12 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
             return true;
         }
 
-        private static Boolean GetTimeOfNNN(DateTimeFormatInfo dtfi, ref DateTimeResult result, ref DateTimeRawInfo raw)
+        private static Boolean GetTimeOfNNN(ref DateTimeResult result, ref DateTimeRawInfo raw)
         {
             if ((result.flags & ParseFlags.HaveTime) != 0)
             {
                 // Multiple times in the input string
-                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                result.SetBadDateTimeFailure();
                 return false;
             }
             Debug.Assert(raw.numCount >= 3, "raw.numCount >= 3");
@@ -2104,7 +2091,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
         {
             if (raw.numCount != 1 || result.Day != -1)
             {
-                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                result.SetBadDateTimeFailure();
                 return false;
             }
             result.Day = raw.GetNumber(0);
@@ -2116,19 +2103,19 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
             if (result.Month == -1)
             {
                 //Should have a month suffix
-                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                result.SetBadDateTimeFailure();
                 return false;
             }
             if (result.Year != -1)
             {
-                // Aleady has a year suffix
-                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                // Already has a year suffix
+                result.SetBadDateTimeFailure();
                 return false;
             }
             if (!TryAdjustYear(ref result, raw.GetNumber(0), out result.Year))
             {
                 // the year value is out of range
-                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                result.SetBadDateTimeFailure();
                 return false;
             }
             result.Day = 1;
@@ -2178,7 +2165,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                     }
                 }
             }
-            result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+            result.SetBadDateTimeFailure();
             return false;
         }
 
@@ -2249,7 +2236,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
         //
         ////////////////////////////////////////////////////////////////////////
 
-        internal static Boolean ProcessHebrewTerminalState(DS dps, ref DateTimeResult result, ref DateTimeStyles styles, ref DateTimeRawInfo raw, DateTimeFormatInfo dtfi)
+        internal static Boolean ProcessHebrewTerminalState(DS dps, ref __DTString str, ref DateTimeResult result, ref DateTimeStyles styles, ref DateTimeRawInfo raw, DateTimeFormatInfo dtfi)
         {
             // The following are accepted terminal state for Hebrew date.
             switch (dps)
@@ -2259,7 +2246,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                     raw.year = raw.GetNumber(1);
                     if (!dtfi.YearMonthAdjustment(ref raw.year, ref raw.month, true))
                     {
-                        result.SetFailure(ParseFailureKind.FormatBadDateTimeCalendar, nameof(SR.Format_BadDateTimeCalendar), null);
+                        result.SetFailure(ParseFailureKind.FormatBadDateTimeCalendar, nameof(SR.Format_BadDateTimeCalendar));
                         return false;
                     }
                     if (!GetDayOfMNN(ref result, ref raw, dtfi))
@@ -2271,10 +2258,10 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                     // Deal with the default long/short date format when the year number is NOT ambigous (i.e. year >= 100).
                     if (!dtfi.YearMonthAdjustment(ref raw.year, ref raw.month, true))
                     {
-                        result.SetFailure(ParseFailureKind.FormatBadDateTimeCalendar, nameof(SR.Format_BadDateTimeCalendar), null);
+                        result.SetFailure(ParseFailureKind.FormatBadDateTimeCalendar, nameof(SR.Format_BadDateTimeCalendar));
                         return false;
                     }
-                    if (!GetDayOfYMN(ref result, ref raw, dtfi))
+                    if (!GetDayOfYMN(ref result, ref raw))
                     {
                         return false;
                     }
@@ -2292,7 +2279,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                     }
                     if (!dtfi.YearMonthAdjustment(ref result.Year, ref raw.month, true))
                     {
-                        result.SetFailure(ParseFailureKind.FormatBadDateTimeCalendar, nameof(SR.Format_BadDateTimeCalendar), null);
+                        result.SetFailure(ParseFailureKind.FormatBadDateTimeCalendar, nameof(SR.Format_BadDateTimeCalendar));
                         return false;
                     }
                     break;
@@ -2302,7 +2289,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                     GetDefaultYear(ref result, ref styles);
                     if (!dtfi.YearMonthAdjustment(ref result.Year, ref raw.month, true))
                     {
-                        result.SetFailure(ParseFailureKind.FormatBadDateTimeCalendar, nameof(SR.Format_BadDateTimeCalendar), null);
+                        result.SetFailure(ParseFailureKind.FormatBadDateTimeCalendar, nameof(SR.Format_BadDateTimeCalendar));
                         return false;
                     }
                     if (!GetHebrewDayOfNM(ref result, ref raw, dtfi))
@@ -2314,35 +2301,35 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                     // Deal with Year/Month pattern.
                     if (!dtfi.YearMonthAdjustment(ref raw.year, ref raw.month, true))
                     {
-                        result.SetFailure(ParseFailureKind.FormatBadDateTimeCalendar, nameof(SR.Format_BadDateTimeCalendar), null);
+                        result.SetFailure(ParseFailureKind.FormatBadDateTimeCalendar, nameof(SR.Format_BadDateTimeCalendar));
                         return false;
                     }
-                    if (!GetDayOfYM(ref result, ref raw, dtfi))
+                    if (!GetDayOfYM(ref result, ref raw))
                     {
                         return false;
                     }
                     break;
                 case DS.TX_N:
                     // Deal hour + AM/PM
-                    if (!GetTimeOfN(dtfi, ref result, ref raw))
+                    if (!GetTimeOfN(ref result, ref raw))
                     {
                         return false;
                     }
                     break;
                 case DS.TX_NN:
-                    if (!GetTimeOfNN(dtfi, ref result, ref raw))
+                    if (!GetTimeOfNN(ref result, ref raw))
                     {
                         return false;
                     }
                     break;
                 case DS.TX_NNN:
-                    if (!GetTimeOfNNN(dtfi, ref result, ref raw))
+                    if (!GetTimeOfNNN(ref result, ref raw))
                     {
                         return false;
                     }
                     break;
                 default:
-                    result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                    result.SetBadDateTimeFailure();
                     return false;
             }
             if (dps > DS.ERROR)
@@ -2359,7 +2346,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
         // A terminal state has been reached, call the appropriate function to fill in the parsing result.
         // Return true if the state is a terminal state.
         //
-        internal static Boolean ProcessTerminaltState(DS dps, ref DateTimeResult result, ref DateTimeStyles styles, ref DateTimeRawInfo raw, DateTimeFormatInfo dtfi)
+        internal static Boolean ProcessTerminalState(DS dps, ref __DTString str, ref DateTimeResult result, ref DateTimeStyles styles, ref DateTimeRawInfo raw, DateTimeFormatInfo dtfi)
         {
             bool passed = true;
             switch (dps)
@@ -2390,22 +2377,22 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                     passed = GetDayOfNNY(ref result, ref raw, dtfi);
                     break;
                 case DS.DX_YMN:
-                    passed = GetDayOfYMN(ref result, ref raw, dtfi);
+                    passed = GetDayOfYMN(ref result, ref raw);
                     break;
                 case DS.DX_YN:
-                    passed = GetDayOfYN(ref result, ref raw, dtfi);
+                    passed = GetDayOfYN(ref result, ref raw);
                     break;
                 case DS.DX_YM:
-                    passed = GetDayOfYM(ref result, ref raw, dtfi);
+                    passed = GetDayOfYM(ref result, ref raw);
                     break;
                 case DS.TX_N:
-                    passed = GetTimeOfN(dtfi, ref result, ref raw);
+                    passed = GetTimeOfN(ref result, ref raw);
                     break;
                 case DS.TX_NN:
-                    passed = GetTimeOfNN(dtfi, ref result, ref raw);
+                    passed = GetTimeOfNN(ref result, ref raw);
                     break;
                 case DS.TX_NNN:
-                    passed = GetTimeOfNNN(dtfi, ref result, ref raw);
+                    passed = GetTimeOfNNN(ref result, ref raw);
                     break;
                 case DS.TX_TS:
                     // The result has got the correct value. Nothing to do.
@@ -2441,7 +2428,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
         internal static DateTime Parse(ReadOnlySpan<char> s, DateTimeFormatInfo dtfi, DateTimeStyles styles)
         {
             DateTimeResult result = new DateTimeResult();       // The buffer to store the parsing result.
-            result.Init();
+            result.Init(s);
             if (TryParse(s, dtfi, styles, ref result))
             {
                 return result.parsedDate;
@@ -2455,7 +2442,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
         internal static DateTime Parse(ReadOnlySpan<char> s, DateTimeFormatInfo dtfi, DateTimeStyles styles, out TimeSpan offset)
         {
             DateTimeResult result = new DateTimeResult();       // The buffer to store the parsing result.
-            result.Init();
+            result.Init(s);
             result.flags |= ParseFlags.CaptureOffset;
             if (TryParse(s, dtfi, styles, ref result))
             {
@@ -2473,7 +2460,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
         {
             result = DateTime.MinValue;
             DateTimeResult resultData = new DateTimeResult();       // The buffer to store the parsing result.
-            resultData.Init();
+            resultData.Init(s);
             if (TryParse(s, dtfi, styles, ref resultData))
             {
                 result = resultData.parsedDate;
@@ -2487,7 +2474,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
             result = DateTime.MinValue;
             offset = TimeSpan.Zero;
             DateTimeResult parseResult = new DateTimeResult();       // The buffer to store the parsing result.
-            parseResult.Init();
+            parseResult.Init(s);
             parseResult.flags |= ParseFlags.CaptureOffset;
             if (TryParse(s, dtfi, styles, ref parseResult))
             {
@@ -2506,7 +2493,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
         {
             if (s.Length == 0)
             {
-                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                result.SetFailure(ParseFailureKind.FormatWithParameter, nameof(SR.Format_BadDateTime));
                 return false;
             }
 
@@ -2575,7 +2562,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                     {
                         if (!ProcessDateTimeSuffix(ref result, ref raw, ref dtok))
                         {
-                            result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                            result.SetBadDateTimeFailure();
                             TPTraceExit("0010", dps);
                             return false;
                         }
@@ -2594,7 +2581,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                         }
                         else
                         {
-                            result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                            result.SetBadDateTimeFailure();
                             TPTraceExit("0030", dps);
                             return false;
                         }
@@ -2604,7 +2591,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                     {
                         if (dtok.dtt == DTT.YearEnd || dtok.dtt == DTT.YearSpace || dtok.dtt == DTT.YearDateSep)
                         {
-                            // When time and date separators are same and we are hitting a year number while the first parsed part of the string was recognized 
+                            // When time and date separators are same and we are hitting a year number while the first parsed part of the string was recognized
                             // as part of time (and not a date) DS.T_Nt, DS.T_NNt then change the state to be a date so we try to parse it as a date instead
                             if (dps == DS.T_Nt)
                             {
@@ -2621,7 +2608,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                         {
                             switch (dtok.dtt)
                             {
-                                // we have the case of Serbia have dates in forms 'd.M.yyyy.' so we can expect '.' after the date parts. 
+                                // we have the case of Serbia have dates in forms 'd.M.yyyy.' so we can expect '.' after the date parts.
                                 // changing the token to end with space instead of Date Separator will avoid failing the parsing.
 
                                 case DTT.YearDateSep: dtok.dtt = atEnd ? DTT.YearEnd : DTT.YearSpace; break;
@@ -2639,7 +2626,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
 
                     if (dps == DS.ERROR)
                     {
-                        result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                        result.SetBadDateTimeFailure();
                         TPTraceExit("0040 (invalid state transition)", dps);
                         return false;
                     }
@@ -2647,7 +2634,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                     {
                         if ((dtfi.FormatFlags & DateTimeFormatFlags.UseHebrewRule) != 0)
                         {
-                            if (!ProcessHebrewTerminalState(dps, ref result, ref styles, ref raw, dtfi))
+                            if (!ProcessHebrewTerminalState(dps, ref str, ref result, ref styles, ref raw, dtfi))
                             {
                                 TPTraceExit("0050 (ProcessHebrewTerminalState)", dps);
                                 return false;
@@ -2655,7 +2642,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                         }
                         else
                         {
-                            if (!ProcessTerminaltState(dps, ref result, ref styles, ref raw, dtfi))
+                            if (!ProcessTerminalState(dps, ref str, ref result, ref styles, ref raw, dtfi))
                             {
                                 TPTraceExit("0060 (ProcessTerminaltState)", dps);
                                 return false;
@@ -2675,7 +2662,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
 
             if (!reachTerminalState)
             {
-                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                result.SetBadDateTimeFailure();
                 TPTraceExit("0070 (did not reach terminal state)", dps);
                 return false;
             }
@@ -2683,7 +2670,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
             AdjustTimeMark(dtfi, ref raw);
             if (!AdjustHour(ref result.Hour, raw.timeMark))
             {
-                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                result.SetBadDateTimeFailure();
                 TPTraceExit("0080 (AdjustHour)", dps);
                 return false;
             }
@@ -2704,7 +2691,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
             if (!result.calendar.TryToDateTime(result.Year, result.Month, result.Day,
                     result.Hour, result.Minute, result.Second, 0, result.era, out time))
             {
-                result.SetFailure(ParseFailureKind.FormatBadDateTimeCalendar, nameof(SR.Format_BadDateTimeCalendar), null);
+                result.SetFailure(ParseFailureKind.FormatBadDateTimeCalendar, nameof(SR.Format_BadDateTimeCalendar));
                 TPTraceExit("0100 (result.calendar.TryToDateTime)", dps);
                 return false;
             }
@@ -2715,7 +2702,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
 
             //
             // We have to check day of week before we adjust to the time zone.
-            // Otherwise, the value of day of week may change after adjustting to the time zone.
+            // Otherwise, the value of day of week may change after adjusting to the time zone.
             //
             if (raw.dayOfWeek != -1)
             {
@@ -2724,7 +2711,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                 //
                 if (raw.dayOfWeek != (int)result.calendar.GetDayOfWeek(time))
                 {
-                    result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDayOfWeek), null);
+                    result.SetFailure(ParseFailureKind.FormatWithOriginalDateTime, nameof(SR.Format_BadDayOfWeek));
                     TPTraceExit("0110 (dayOfWeek check)", dps);
                     return false;
                 }
@@ -2732,7 +2719,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
 
             result.parsedDate = time;
 
-            if (!DetermineTimeZoneAdjustments(ref result, styles, bTimeOnly))
+            if (!DetermineTimeZoneAdjustments(ref str, ref result, styles, bTimeOnly))
             {
                 TPTraceExit("0120 (DetermineTimeZoneAdjustments)", dps);
                 return false;
@@ -2743,13 +2730,13 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
 
 
         // Handles time zone adjustments and sets DateTimeKind values as required by the styles
-        private static Boolean DetermineTimeZoneAdjustments(ref DateTimeResult result, DateTimeStyles styles, Boolean bTimeOnly)
+        private static Boolean DetermineTimeZoneAdjustments(ref __DTString str, ref DateTimeResult result, DateTimeStyles styles, Boolean bTimeOnly)
         {
             if ((result.flags & ParseFlags.CaptureOffset) != 0)
             {
-                // This is a DateTimeOffset parse, so the offset will actually be captured directly, and 
+                // This is a DateTimeOffset parse, so the offset will actually be captured directly, and
                 // no adjustment is required in most cases
-                return DateTimeOffsetTimeZonePostProcessing(ref result, styles);
+                return DateTimeOffsetTimeZonePostProcessing(ref str, ref result, styles);
             }
             else
             {
@@ -2758,7 +2745,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                 // the DateTime offset must be within +- 14:00 hours.
                 if (offsetTicks < DateTimeOffset.MinOffset || offsetTicks > DateTimeOffset.MaxOffset)
                 {
-                    result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_OffsetOutOfRange), null);
+                    result.SetFailure(ParseFailureKind.FormatWithOriginalDateTime, nameof(SR.Format_OffsetOutOfRange));
                     return false;
                 }
             }
@@ -2821,9 +2808,9 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
         }
 
         // Apply validation and adjustments specific to DateTimeOffset
-        private static Boolean DateTimeOffsetTimeZonePostProcessing(ref DateTimeResult result, DateTimeStyles styles)
+        private static Boolean DateTimeOffsetTimeZonePostProcessing(ref __DTString str, ref DateTimeResult result, DateTimeStyles styles)
         {
-            // For DateTimeOffset, default to the Utc or Local offset when an offset was not specified by 
+            // For DateTimeOffset, default to the Utc or Local offset when an offset was not specified by
             // the input string.
             if ((result.flags & ParseFlags.TimeZoneUsed) == 0)
             {
@@ -2846,17 +2833,17 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
             Int64 utcTicks = result.parsedDate.Ticks - offsetTicks;
 
             // For DateTimeOffset, both the parsed time and the corresponding UTC value must be within the boundaries
-            // of a DateTime instance.            
+            // of a DateTime instance.
             if (utcTicks < DateTime.MinTicks || utcTicks > DateTime.MaxTicks)
             {
-                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_UTCOutOfRange), null);
+                result.SetFailure(ParseFailureKind.FormatWithOriginalDateTime, nameof(SR.Format_UTCOutOfRange));
                 return false;
             }
 
             // the offset must be within +- 14:00 hours.
             if (offsetTicks < DateTimeOffset.MinOffset || offsetTicks > DateTimeOffset.MaxOffset)
             {
-                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_OffsetOutOfRange), null);
+                result.SetFailure(ParseFailureKind.FormatWithOriginalDateTime, nameof(SR.Format_OffsetOutOfRange));
                 return false;
             }
 
@@ -2873,7 +2860,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                 }
 
                 // The constructor should always succeed because of the range check earlier in the function
-                // Althought it is UTC, internally DateTimeOffset does not use this flag
+                // Although it is UTC, internally DateTimeOffset does not use this flag
                 result.parsedDate = new DateTime(utcTicks, DateTimeKind.Utc);
                 result.timeZoneOffset = TimeSpan.Zero;
             }
@@ -2899,7 +2886,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
 
             if (resultTicks < DateTime.MinTicks || resultTicks > DateTime.MaxTicks)
             {
-                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_DateOutOfRange), null);
+                result.SetFailure(ParseFailureKind.FormatWithOriginalDateTime, nameof(SR.Format_DateOutOfRange));
                 return false;
             }
             result.parsedDate = new DateTime(resultTicks, DateTimeKind.Utc);
@@ -2956,7 +2943,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
             if (resultTicks < DateTime.MinTicks || resultTicks > DateTime.MaxTicks)
             {
                 result.parsedDate = DateTime.MinValue;
-                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_DateOutOfRange), null);
+                result.SetFailure(ParseFailureKind.FormatWithOriginalDateTime, nameof(SR.Format_DateOutOfRange));
                 return false;
             }
             result.parsedDate = new DateTime(resultTicks, DateTimeKind.Local, isAmbiguousLocalDst);
@@ -2980,19 +2967,19 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
             str.SkipWhiteSpaces();
             if (!ParseDigits(ref str, 2, out hour))
             {
-                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                result.SetBadDateTimeFailure();
                 return false;
             }
             str.SkipWhiteSpaces();
             if (!str.Match(':'))
             {
-                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                result.SetBadDateTimeFailure();
                 return false;
             }
             str.SkipWhiteSpaces();
             if (!ParseDigits(ref str, 2, out minute))
             {
-                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                result.SetBadDateTimeFailure();
                 return false;
             }
             str.SkipWhiteSpaces();
@@ -3001,14 +2988,14 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                 str.SkipWhiteSpaces();
                 if (!ParseDigits(ref str, 2, out second))
                 {
-                    result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                    result.SetBadDateTimeFailure();
                     return false;
                 }
                 if (str.Match('.'))
                 {
                     if (!ParseFraction(ref str, out partSecond))
                     {
-                        result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                        result.SetBadDateTimeFailure();
                         return false;
                     }
                     str.Index--;
@@ -3023,7 +3010,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                     result.flags |= ParseFlags.TimeZoneUsed;
                     if (!ParseTimeZone(ref str, ref result.timeZoneOffset))
                     {
-                        result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                        result.SetBadDateTimeFailure();
                         return false;
                     }
                 }
@@ -3042,7 +3029,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                 {
                     if (!VerifyValidPunctuation(ref str))
                     {
-                        result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                        result.SetBadDateTimeFailure();
                         return false;
                     }
                     str.SkipWhiteSpaces();
@@ -3051,14 +3038,14 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                 {
                     if (!VerifyValidPunctuation(ref str))
                     {
-                        result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                        result.SetBadDateTimeFailure();
                         return false;
                     }
                 }
                 if (str.GetNext())
                 {
                     // If this is true, there were non-white space characters remaining in the DateTime
-                    result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                    result.SetBadDateTimeFailure();
                     return false;
                 }
             }
@@ -3068,13 +3055,13 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
             if (!calendar.TryToDateTime(raw.year, raw.GetNumber(0), raw.GetNumber(1),
                     hour, minute, second, 0, result.era, out time))
             {
-                result.SetFailure(ParseFailureKind.FormatBadDateTimeCalendar, nameof(SR.Format_BadDateTimeCalendar), null);
+                result.SetFailure(ParseFailureKind.FormatBadDateTimeCalendar, nameof(SR.Format_BadDateTimeCalendar));
                 return false;
             }
 
             time = time.AddTicks((long)Math.Round(partSecond * Calendar.TicksPerSecond));
             result.parsedDate = time;
-            if (!DetermineTimeZoneAdjustments(ref result, styles, false))
+            if (!DetermineTimeZoneAdjustments(ref str, ref result, styles, false))
             {
                 return false;
             }
@@ -3620,15 +3607,18 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
             // change the code below.
             if (str.GetNext())
             {
-                if (str.GetChar() == dtfi.AMDesignator[0])
+                string amDesignator = dtfi.AMDesignator;
+                if (amDesignator.Length > 0 && str.GetChar() == amDesignator[0])
                 {
                     result = TM.AM;
-                    return (true);
+                    return true;
                 }
-                if (str.GetChar() == dtfi.PMDesignator[0])
+
+                string pmDesignator = dtfi.PMDesignator;
+                if (pmDesignator.Length > 0 && str.GetChar() == pmDesignator[0])
                 {
                     result = TM.PM;
-                    return (true);
+                    return true;
                 }
             }
             return false;
@@ -3678,7 +3668,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                 }
             }
 
-            // assume the offset is Local            
+            // assume the offset is Local
             return DateTime.Now;
         }
 
@@ -3699,7 +3689,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                 if (((result.Month != -1) || (result.Day != -1))
                     && ((result.Year == -1 || ((result.flags & ParseFlags.YearDefault) != 0)) && (result.flags & ParseFlags.TimeZoneUsed) != 0))
                 {
-                    result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_MissingIncompleteDate), null);
+                    result.SetFailure(ParseFailureKind.FormatWithOriginalDateTime, nameof(SR.Format_MissingIncompleteDate));
                     return false;
                 }
             }
@@ -3784,7 +3774,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
         // This method also set the dtfi according/parseInfo to some special pre-defined
         // formats.
         //
-        private static String ExpandPredefinedFormat(String format, ref DateTimeFormatInfo dtfi, ref ParsingInfo parseInfo, ref DateTimeResult result)
+        private static String ExpandPredefinedFormat(ReadOnlySpan<char> format, ref DateTimeFormatInfo dtfi, ref ParsingInfo parseInfo, ref DateTimeResult result)
         {
             //
             // Check the format to see if we need to override the dtfi to be InvariantInfo,
@@ -3882,7 +3872,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                     }
                     if (!parseResult)
                     {
-                        result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                        result.SetBadDateTimeFailure();
                         return (false);
                     }
                     if (!CheckNewValue(ref result.Year, tempYear, ch, ref result))
@@ -3899,7 +3889,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                             if (!parseInfo.fCustomNumberParser ||
                                 !parseInfo.parseNumberDelegate(ref str, tokenLen, out tempMonth))
                             {
-                                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                                result.SetBadDateTimeFailure();
                                 return (false);
                             }
                         }
@@ -3910,7 +3900,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                         {
                             if (!MatchAbbreviatedMonthName(ref str, dtfi, ref tempMonth))
                             {
-                                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                                result.SetBadDateTimeFailure();
                                 return (false);
                             }
                         }
@@ -3918,7 +3908,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                         {
                             if (!MatchMonthName(ref str, dtfi, ref tempMonth))
                             {
-                                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                                result.SetBadDateTimeFailure();
                                 return (false);
                             }
                         }
@@ -3941,7 +3931,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                             if (!parseInfo.fCustomNumberParser ||
                                 !parseInfo.parseNumberDelegate(ref str, tokenLen, out tempDay))
                             {
-                                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                                result.SetBadDateTimeFailure();
                                 return (false);
                             }
                         }
@@ -3957,7 +3947,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                             // "ddd"
                             if (!MatchAbbreviatedDayName(ref str, dtfi, ref tempDayOfWeek))
                             {
-                                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                                result.SetBadDateTimeFailure();
                                 return (false);
                             }
                         }
@@ -3966,7 +3956,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                             // "dddd*"
                             if (!MatchDayName(ref str, dtfi, ref tempDayOfWeek))
                             {
-                                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                                result.SetBadDateTimeFailure();
                                 return (false);
                             }
                         }
@@ -3981,7 +3971,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                     // Put the era value in result.era.
                     if (!MatchEraName(ref str, dtfi, ref result.era))
                     {
-                        result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                        result.SetBadDateTimeFailure();
                         return (false);
                     }
                     break;
@@ -3990,7 +3980,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                     tokenLen = format.GetRepeatCount();
                     if (!ParseDigits(ref str, (tokenLen < 2 ? 1 : 2), out tempHour))
                     {
-                        result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                        result.SetBadDateTimeFailure();
                         return (false);
                     }
                     if (!CheckNewValue(ref result.Hour, tempHour, ch, ref result))
@@ -4002,7 +3992,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                     tokenLen = format.GetRepeatCount();
                     if (!ParseDigits(ref str, (tokenLen < 2 ? 1 : 2), out tempHour))
                     {
-                        result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                        result.SetBadDateTimeFailure();
                         return (false);
                     }
                     if (!CheckNewValue(ref result.Hour, tempHour, ch, ref result))
@@ -4014,7 +4004,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                     tokenLen = format.GetRepeatCount();
                     if (!ParseDigits(ref str, (tokenLen < 2 ? 1 : 2), out tempMinute))
                     {
-                        result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                        result.SetBadDateTimeFailure();
                         return (false);
                     }
                     if (!CheckNewValue(ref result.Minute, tempMinute, ch, ref result))
@@ -4026,7 +4016,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                     tokenLen = format.GetRepeatCount();
                     if (!ParseDigits(ref str, (tokenLen < 2 ? 1 : 2), out tempSecond))
                     {
-                        result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                        result.SetBadDateTimeFailure();
                         return (false);
                     }
                     if (!CheckNewValue(ref result.Second, tempSecond, ch, ref result))
@@ -4043,7 +4033,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                         {
                             if (ch == 'f')
                             {
-                                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                                result.SetBadDateTimeFailure();
                                 return (false);
                             }
                         }
@@ -4062,7 +4052,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                     }
                     else
                     {
-                        result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                        result.SetBadDateTimeFailure();
                         return (false);
                     }
                     break;
@@ -4073,7 +4063,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                     {
                         if (!MatchAbbreviatedTimeMark(ref str, dtfi, ref tempTimeMark))
                         {
-                            result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                            result.SetBadDateTimeFailure();
                             return (false);
                         }
                     }
@@ -4081,7 +4071,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                     {
                         if (!MatchTimeMark(ref str, dtfi, ref tempTimeMark))
                         {
-                            result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                            result.SetBadDateTimeFailure();
                             return (false);
                         }
                     }
@@ -4106,7 +4096,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                         TimeSpan tempTimeZoneOffset = new TimeSpan(0);
                         if (!ParseTimeZoneOffset(ref str, tokenLen, ref tempTimeZoneOffset))
                         {
-                            result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                            result.SetBadDateTimeFailure();
                             return (false);
                         }
                         if ((result.flags & ParseFlags.TimeZoneUsed) != 0 && tempTimeZoneOffset != result.timeZoneOffset)
@@ -4136,7 +4126,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                     str.Index++;
                     if (!GetTimeZoneName(ref str))
                     {
-                        result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                        result.SetBadDateTimeFailure();
                         return false;
                     }
                     str.Index--;
@@ -4161,7 +4151,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                         TimeSpan tempTimeZoneOffset = new TimeSpan(0);
                         if (!ParseTimeZoneOffset(ref str, 3, ref tempTimeZoneOffset))
                         {
-                            result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                            result.SetBadDateTimeFailure();
                             return (false);
                         }
                         if ((result.flags & ParseFlags.TimeZoneUsed) != 0 && tempTimeZoneOffset != result.timeZoneOffset)
@@ -4181,7 +4171,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                         !str.Match(dtfi.TimeSeparator))
                     {
                         // A time separator is expected.
-                        result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                        result.SetBadDateTimeFailure();
                         return false;
                     }
                     break;
@@ -4192,7 +4182,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                         !str.Match(dtfi.DateSeparator))
                     {
                         // A date separator is expected.
-                        result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                        result.SetBadDateTimeFailure();
                         return false;
                     }
                     break;
@@ -4222,13 +4212,13 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                         else if (!str.Match(quotedStr[i]))
                         {
                             // Can not find the matching quoted string.
-                            result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                            result.SetBadDateTimeFailure();
                             return false;
                         }
                     }
 
                     // The "r" and "u" formats incorrectly quoted 'GMT' and 'Z', respectively.  We cannot
-                    // correct this mistake for DateTime.ParseExact for compatibility reasons, but we can 
+                    // correct this mistake for DateTime.ParseExact for compatibility reasons, but we can
                     // fix it for DateTimeOffset.ParseExact as DateTimeOffset has not been publically released
                     // with this issue.
                     if ((result.flags & ParseFlags.CaptureOffset) != 0)
@@ -4253,7 +4243,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                     // Make sure the next character is not a '%' again.
                     if (format.Index >= format.Value.Length - 1 || format.Value[format.Index + 1] == '%')
                     {
-                        result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadFormatSpecifier), null);
+                        result.SetBadFormatSpecifierFailure(format.Value);
                         return false;
                     }
                     break;
@@ -4266,13 +4256,13 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                         if (!str.Match(format.GetChar()))
                         {
                             // Can not find a match for the escaped character.
-                            result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                            result.SetBadDateTimeFailure();
                             return false;
                         }
                     }
                     else
                     {
-                        result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadFormatSpecifier), null);
+                        result.SetBadFormatSpecifierFailure(format.Value);
                         return false;
                     }
                     break;
@@ -4289,7 +4279,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                                 break;
                             }
                         }
-                        result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                        result.SetBadDateTimeFailure();
                         return false;
                     }
                     break;
@@ -4324,7 +4314,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                                         }
                                     }
                                 }
-                                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                                result.SetBadDateTimeFailure();
                                 return false;
                             }
                             // Found a macth.
@@ -4341,14 +4331,14 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                             result.timeZoneOffset = TimeSpan.Zero;
                             if (!str.Match(GMTName))
                             {
-                                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                                result.SetBadDateTimeFailure();
                                 return false;
                             }
                         }
                         else if (!str.Match(ch))
                         {
                             // ch is expected.
-                            result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                            result.SetBadDateTimeFailure();
                             return false;
                         }
                     }
@@ -4439,7 +4429,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
 
         private static bool DoStrictParse(
             ReadOnlySpan<char> s,
-            String formatParam,
+            ReadOnlySpan<char> formatParam,
             DateTimeStyles styles,
             DateTimeFormatInfo dtfi,
             ref DateTimeResult result)
@@ -4451,15 +4441,12 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
             parseInfo.fAllowInnerWhite = ((styles & DateTimeStyles.AllowInnerWhite) != 0);
             parseInfo.fAllowTrailingWhite = ((styles & DateTimeStyles.AllowTrailingWhite) != 0);
 
-            // We need the original values of the following two below.
-            String originalFormat = formatParam;
-
             if (formatParam.Length == 1)
             {
                 if (((result.flags & ParseFlags.CaptureOffset) != 0) && formatParam[0] == 'U')
                 {
                     // The 'U' format is not allowed for DateTimeOffset
-                    result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadFormatSpecifier), null);
+                    result.SetBadFormatSpecifierFailure(formatParam);
                     return false;
                 }
                 formatParam = ExpandPredefinedFormat(formatParam, ref dtfi, ref parseInfo, ref result);
@@ -4478,7 +4465,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
             // if we have parsed every item twice.
             result.Hour = result.Minute = result.Second = -1;
 
-            __DTString format = new __DTString(formatParam.AsReadOnlySpan(), dtfi, false);
+            __DTString format = new __DTString(formatParam, dtfi, false);
             __DTString str = new __DTString(s, dtfi, false);
 
             if (parseInfo.fAllowTrailingWhite)
@@ -4516,7 +4503,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
             if (str.Index < str.Value.Length - 1)
             {
                 // There are still remaining character in str.
-                result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                result.SetBadDateTimeFailure();
                 return false;
             }
 
@@ -4525,16 +4512,16 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                 // A two digit year value is expected. Check if the parsed year value is valid.
                 if (result.Year >= 100)
                 {
-                    result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                    result.SetBadDateTimeFailure();
                     return false;
                 }
                 try
                 {
                     result.Year = parseInfo.calendar.ToFourDigitYear(result.Year);
                 }
-                catch (ArgumentOutOfRangeException e)
+                catch (ArgumentOutOfRangeException)
                 {
-                    result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), e);
+                    result.SetBadDateTimeFailure();
                     return false;
                 }
             }
@@ -4553,7 +4540,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                 if (result.Hour > 12)
                 {
                     // AM/PM is used, but the value for HH is too big.
-                    result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                    result.SetBadDateTimeFailure();
                     return false;
                 }
                 if (parseInfo.timeMark == TM.AM)
@@ -4577,7 +4564,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                 if ((parseInfo.timeMark == TM.AM && result.Hour >= 12)
                     || (parseInfo.timeMark == TM.PM && result.Hour < 12))
                 {
-                    result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+                    result.SetBadDateTimeFailure();
                     return false;
                 }
             }
@@ -4594,14 +4581,14 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
             {
                 if (!dtfi.YearMonthAdjustment(ref result.Year, ref result.Month, ((result.flags & ParseFlags.ParsedMonthName) != 0)))
                 {
-                    result.SetFailure(ParseFailureKind.FormatBadDateTimeCalendar, nameof(SR.Format_BadDateTimeCalendar), null);
+                    result.SetFailure(ParseFailureKind.FormatBadDateTimeCalendar, nameof(SR.Format_BadDateTimeCalendar));
                     return false;
                 }
             }
             if (!parseInfo.calendar.TryToDateTime(result.Year, result.Month, result.Day,
                     result.Hour, result.Minute, result.Second, 0, result.era, out result.parsedDate))
             {
-                result.SetFailure(ParseFailureKind.FormatBadDateTimeCalendar, nameof(SR.Format_BadDateTimeCalendar), null);
+                result.SetFailure(ParseFailureKind.FormatBadDateTimeCalendar, nameof(SR.Format_BadDateTimeCalendar));
                 return false;
             }
             if (result.fraction > 0)
@@ -4621,13 +4608,13 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                 //
                 if (parseInfo.dayOfWeek != (int)parseInfo.calendar.GetDayOfWeek(result.parsedDate))
                 {
-                    result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDayOfWeek), null);
+                    result.SetFailure(ParseFailureKind.FormatWithOriginalDateTime, nameof(SR.Format_BadDayOfWeek));
                     return false;
                 }
             }
 
 
-            if (!DetermineTimeZoneAdjustments(ref result, styles, bTimeOnly))
+            if (!DetermineTimeZoneAdjustments(ref str, ref result, styles, bTimeOnly))
             {
                 return false;
             }
@@ -4645,73 +4632,72 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                 case ParseFailureKind.FormatWithParameter:
                     return new FormatException(SR.Format(SR.GetResourceString(result.failureMessageID), result.failureMessageFormatArgument));
                 case ParseFailureKind.FormatBadDateTimeCalendar:
-                    return new FormatException(SR.Format(SR.GetResourceString(result.failureMessageID), result.calendar));
+                    return new FormatException(SR.Format(SR.GetResourceString(result.failureMessageID), new string(result.originalDateTimeString), result.calendar));
+                case ParseFailureKind.FormatWithOriginalDateTime:
+                    return new FormatException(SR.Format(SR.GetResourceString(result.failureMessageID), new string(result.originalDateTimeString)));
+                case ParseFailureKind.FormatWithFormatSpecifier:
+                    return new FormatException(SR.Format(SR.GetResourceString(result.failureMessageID), new string(result.failedFormatSpecifier)));
+                case ParseFailureKind.FormatWithOriginalDateTimeAndParameter:
+                    return new FormatException(SR.Format(SR.GetResourceString(result.failureMessageID), new string(result.originalDateTimeString), result.failureMessageFormatArgument));
                 default:
-                    Debug.Assert(false, "Unkown DateTimeParseFailure: " + result);
+                    Debug.Fail("Unknown DateTimeParseFailure: " + result.failure.ToString());
                     return null;
             }
         }
 
-        // Builds with _LOGGING defined (x86dbg, amd64chk, etc) support tracing
-        // Set the following internal-only/unsupported environment variables to enable DateTime tracing to the console:
-        //
-        // COMPlus_LogEnable=1
-        // COMPlus_LogToConsole=1
-        // COMPlus_LogLevel=9
-        // COMPlus_ManagedLogFacility=0x00001000
         [Conditional("_LOGGING")]
-        internal static void LexTraceExit(string message, DS dps)
+        private static void LexTraceExit(string message, DS dps)
         {
 #if _LOGGING
             if (!_tracingEnabled)
                 return;
-            BCLDebug.Trace("DATETIME", "[DATETIME] Lex return {0}, DS.{1}", message, dps);
+            Trace($"Lex return {message}, DS.{dps}");
 #endif // _LOGGING
         }
         [Conditional("_LOGGING")]
-        internal static void PTSTraceExit(DS dps, bool passed)
+        private static void PTSTraceExit(DS dps, bool passed)
         {
 #if _LOGGING
             if (!_tracingEnabled)
                 return;
-            BCLDebug.Trace("DATETIME", "[DATETIME] ProcessTerminalState {0} @ DS.{1}", passed ? "passed" : "failed", dps);
+            Trace($"ProcessTerminalState {(passed ? "passed" : "failed")} @ DS.{dps}");
 #endif // _LOGGING
         }
         [Conditional("_LOGGING")]
-        internal static void TPTraceExit(string message, DS dps)
+        private static void TPTraceExit(string message, DS dps)
         {
 #if _LOGGING
             if (!_tracingEnabled)
                 return;
-            BCLDebug.Trace("DATETIME", "[DATETIME] TryParse return {0}, DS.{1}", message, dps);
+            Trace($"TryParse return {message}, DS.{dps}");
 #endif // _LOGGING
         }
         [Conditional("_LOGGING")]
-        internal static void DTFITrace(DateTimeFormatInfo dtfi)
+        private static void DTFITrace(DateTimeFormatInfo dtfi)
         {
 #if _LOGGING
             if (!_tracingEnabled)
                 return;
 
-            BCLDebug.Trace("DATETIME", "[DATETIME] DateTimeFormatInfo Properties");
+            Trace("DateTimeFormatInfo Properties");
 #if !FEATURE_COREFX_GLOBALIZATION
-            BCLDebug.Trace("DATETIME", " NativeCalendarName {0}", Hex(dtfi.NativeCalendarName));
+            Trace($" NativeCalendarName {Hex(dtfi.NativeCalendarName)}");
 #endif
-            BCLDebug.Trace("DATETIME", "       AMDesignator {0}", Hex(dtfi.AMDesignator));
-            BCLDebug.Trace("DATETIME", "       PMDesignator {0}", Hex(dtfi.PMDesignator));
-            BCLDebug.Trace("DATETIME", "      TimeSeparator {0}", Hex(dtfi.TimeSeparator));
-            BCLDebug.Trace("DATETIME", "      AbbrvDayNames {0}", Hex(dtfi.AbbreviatedDayNames));
-            BCLDebug.Trace("DATETIME", "   ShortestDayNames {0}", Hex(dtfi.ShortestDayNames));
-            BCLDebug.Trace("DATETIME", "           DayNames {0}", Hex(dtfi.DayNames));
-            BCLDebug.Trace("DATETIME", "    AbbrvMonthNames {0}", Hex(dtfi.AbbreviatedMonthNames));
-            BCLDebug.Trace("DATETIME", "         MonthNames {0}", Hex(dtfi.MonthNames));
-            BCLDebug.Trace("DATETIME", " AbbrvMonthGenNames {0}", Hex(dtfi.AbbreviatedMonthGenitiveNames));
-            BCLDebug.Trace("DATETIME", "      MonthGenNames {0}", Hex(dtfi.MonthGenitiveNames));
+            Trace($"       AMDesignator {Hex(dtfi.AMDesignator)}");
+            Trace($"       PMDesignator {Hex(dtfi.PMDesignator)}");
+            Trace($"      TimeSeparator {Hex(dtfi.TimeSeparator)}");
+            Trace($"      AbbrvDayNames {Hex(dtfi.AbbreviatedDayNames)}");
+            Trace($"   ShortestDayNames {Hex(dtfi.ShortestDayNames)}");
+            Trace($"           DayNames {Hex(dtfi.DayNames)}");
+            Trace($"    AbbrvMonthNames {Hex(dtfi.AbbreviatedMonthNames)}");
+            Trace($"         MonthNames {Hex(dtfi.MonthNames)}");
+            Trace($" AbbrvMonthGenNames {Hex(dtfi.AbbreviatedMonthGenitiveNames)}");
+            Trace($"      MonthGenNames {Hex(dtfi.MonthGenitiveNames)}");
 #endif // _LOGGING
         }
 #if _LOGGING
         // return a string in the form: "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
-        internal static string Hex(string[] strs)
+        private static string Hex(string[] strs)
         {
             if (strs == null || strs.Length == 0)
                 return String.Empty;
@@ -4764,8 +4750,8 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
             return buffer.ToString();
         }
         // return a string in the form: "Sun"
-        internal static string Hex(string str) => Hex(str.AsReadOnlySpan());
-        internal static string Hex(ReadOnlySpan<char> str)
+        private static string Hex(string str) => Hex((ReadOnlySpan<char>)str);
+        private static string Hex(ReadOnlySpan<char> str)
         {
             StringBuilder buffer = new StringBuilder();
             buffer.Append("\"");
@@ -4780,7 +4766,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
             return buffer.ToString();
         }
         // return an unicode escaped string form of char c
-        internal static String Hex(char c)
+        private static String Hex(char c)
         {
             if (c <= '\x007f')
                 return c.ToString(CultureInfo.InvariantCulture);
@@ -4788,7 +4774,12 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                 return "\\u" + ((int)c).ToString("x4", CultureInfo.InvariantCulture);
         }
 
-        internal static bool _tracingEnabled = BCLDebug.CheckEnabled("DATETIME");
+        private static void Trace(string s)
+        {
+            // Internal.Console.WriteLine(s);
+        }
+
+        private static bool _tracingEnabled = false;
 #endif // _LOGGING
     }
 
@@ -5054,7 +5045,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                         {
                             return false;
                         }
-                        if (m_info.Compare(Value.Slice(thisPosition, segmentLength), target.AsReadOnlySpan().Slice(targetPosition, segmentLength), CompareOptions.IgnoreCase) != 0)
+                        if (m_info.CompareOptionIgnoreCase(Value.Slice(thisPosition, segmentLength), target.AsSpan(targetPosition, segmentLength)) != 0)
                         {
                             return false;
                         }
@@ -5080,7 +5071,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
                     {
                         return false;
                     }
-                    if (m_info.Compare(Value.Slice(thisPosition, segmentLength), target.AsReadOnlySpan().Slice(targetPosition, segmentLength), CompareOptions.IgnoreCase) != 0)
+                    if (m_info.CompareOptionIgnoreCase(Value.Slice(thisPosition, segmentLength), target.AsSpan(targetPosition, segmentLength)) != 0)
                     {
                         return false;
                     }
@@ -5295,14 +5286,17 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
             // Check if the last character is a quote.
             if (ch == '\'' || ch == '\"')
             {
-                if (Char.IsWhiteSpace(Value[i - 1]))
+                if (char.IsWhiteSpace(Value[i - 1]))
                 {
                     i--;
-                    while (i >= 1 && Char.IsWhiteSpace(Value[i - 1]))
+                    while (i >= 1 && char.IsWhiteSpace(Value[i - 1]))
                     {
                         i--;
                     }
-                    Value = Value.Remove(i, Value.Length - 1 - i);
+                    Span<char> result = new char[i + 1];
+                    result[i] = ch;
+                    Value.Slice(0, i).CopyTo(result);
+                    Value = result;
                 }
             }
         }
@@ -5320,13 +5314,16 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
             // Check if the last character is a quote.
             if (ch == '\'' || ch == '\"')
             {
-                while ((i + 1) < Length && Char.IsWhiteSpace(Value[i + 1]))
+                while ((i + 1) < Length && char.IsWhiteSpace(Value[i + 1]))
                 {
                     i++;
                 }
                 if (i != 0)
                 {
-                    Value = Value.Remove(1, i);
+                    Span<char> result = new char[Value.Length - i];
+                    result[0] = ch;
+                    Value.Slice(i + 1).CopyTo(result.Slice(1));
+                    Value = result;
                 }
             }
         }
@@ -5482,7 +5479,10 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
         ArgumentNull = 1,
         Format = 2,
         FormatWithParameter = 3,
-        FormatBadDateTimeCalendar = 4,  // FormatException when ArgumentOutOfRange is thrown by a Calendar.TryToDateTime().
+        FormatWithOriginalDateTime = 4,
+        FormatWithFormatSpecifier = 5,
+        FormatWithOriginalDateTimeAndParameter = 6,
+        FormatBadDateTimeCalendar = 7,  // FormatException when ArgumentOutOfRange is thrown by a Calendar.TryToDateTime().
     };
 
     [Flags]
@@ -5510,7 +5510,7 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
     // used to construct a DateTime instance.
     //
     internal
-    struct DateTimeResult
+    ref struct DateTimeResult
     {
         internal int Year;
         internal int Month;
@@ -5537,9 +5537,12 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
         internal string failureMessageID;
         internal object failureMessageFormatArgument;
         internal string failureArgumentName;
+        internal ReadOnlySpan<char> originalDateTimeString;
+        internal ReadOnlySpan<char> failedFormatSpecifier;
 
-        internal void Init()
+        internal void Init(ReadOnlySpan<char> originalDateTimeString)
         {
+            this.originalDateTimeString = originalDateTimeString;
             Year = -1;
             Month = -1;
             Day = -1;
@@ -5553,6 +5556,33 @@ new DS[] { DS.ERROR, DS.TX_NNN,  DS.TX_NNN,  DS.TX_NNN,  DS.ERROR,   DS.ERROR,
             Month = month;
             Day = day;
         }
+
+        internal void SetBadFormatSpecifierFailure()
+        {
+            SetBadFormatSpecifierFailure(ReadOnlySpan<char>.Empty);
+        }
+
+        internal void SetBadFormatSpecifierFailure(ReadOnlySpan<char> failedFormatSpecifier)
+        {
+            this.failure = ParseFailureKind.FormatWithFormatSpecifier;
+            this.failureMessageID = nameof(SR.Format_BadFormatSpecifier);
+            this.failedFormatSpecifier = failedFormatSpecifier;
+        }
+
+        internal void SetBadDateTimeFailure()
+        {
+            this.failure = ParseFailureKind.FormatWithOriginalDateTime;
+            this.failureMessageID = nameof(SR.Format_BadDateTime);
+            this.failureMessageFormatArgument = null;
+        }
+
+        internal void SetFailure(ParseFailureKind failure, string failureMessageID)
+        {
+            this.failure = failure;
+            this.failureMessageID = failureMessageID;
+            this.failureMessageFormatArgument = null;
+        }
+
         internal void SetFailure(ParseFailureKind failure, string failureMessageID, object failureMessageFormatArgument)
         {
             this.failure = failure;