using System.Diagnostics;
using System.Globalization;
+using System.Runtime.CompilerServices;
using System.Text;
namespace System
internal static MatchNumberDelegate m_hebrewNumberParser = new MatchNumberDelegate(DateTimeParse.MatchHebrewDigits);
- internal static DateTime ParseExact(String 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;
}
}
- internal static DateTime ParseExact(String 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))
{
}
}
- internal static bool TryParseExact(String 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;
return false;
}
- internal static bool TryParseExact(String 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))
{
return false;
}
- internal static bool TryParseExact(String 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 (s == null)
- {
- result.SetFailure(ParseFailureKind.ArgumentNull, nameof(SR.ArgumentNull_String), null, nameof(s));
- return false;
- }
- 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;
}
return DoStrictParse(s, format, style, dtfi, ref result);
}
- internal static DateTime ParseExactMultiple(String s, String[] formats,
+ internal static DateTime ParseExactMultiple(ReadOnlySpan<char> s, String[] formats,
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;
}
- internal static DateTime ParseExactMultiple(String s, String[] formats,
+ internal static DateTime ParseExactMultiple(ReadOnlySpan<char> s, String[] formats,
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 (TryParseExactMultiple(s, formats, dtfi, style, ref result))
{
}
}
- internal static bool TryParseExactMultiple(String s, String[] formats,
+ internal static bool TryParseExactMultiple(ReadOnlySpan<char> s, String[] formats,
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 (TryParseExactMultiple(s, formats, dtfi, style, ref resultData))
{
}
- internal static bool TryParseExactMultiple(String s, String[] formats,
+ internal static bool TryParseExactMultiple(ReadOnlySpan<char> s, String[] formats,
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 (TryParseExactMultiple(s, formats, dtfi, style, ref resultData))
{
result = resultData.parsedDate;
return false;
}
- internal static bool TryParseExactMultiple(String s, String[] formats,
+ internal static bool TryParseExactMultiple(ReadOnlySpan<char> s, String[] formats,
DateTimeFormatInfo dtfi, DateTimeStyles style, ref DateTimeResult result)
{
- if (s == null)
- {
- result.SetFailure(ParseFailureKind.ArgumentNull, nameof(SR.ArgumentNull_String), null, nameof(s));
- return false;
- }
if (formats == null)
{
result.SetFailure(ParseFailureKind.ArgumentNull, nameof(SR.ArgumentNull_String), null, nameof(formats));
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;
}
{
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))
{
return (true);
}
}
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
return (false);
}
//
////////////////////////////////////////////////////////////////////////////
- // 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},
//
private static bool MatchWord(ref __DTString str, String target)
{
- int length = target.Length;
- if (length > (str.Value.Length - str.Index))
+ if (target.Length > (str.Value.Length - str.Index))
{
return false;
}
- if (str.CompareInfo.Compare(str.Value, str.Index, length,
- target, 0, length, CompareOptions.IgnoreCase) != 0)
+ if (str.CompareInfo.Compare(str.Value.Slice(str.Index, target.Length), target, CompareOptions.IgnoreCase) != 0)
{
return (false);
}
}
}
str.Index = nextCharIndex;
- if (str.Index < str.len)
+ if (str.Index < str.Length)
{
str.m_current = str.Value[str.Index];
}
return (false);
}
- internal static bool IsDigit(char ch)
- {
- return (ch >= '0' && ch <= '9');
- }
-
+ internal static bool IsDigit(char ch) => (uint)(ch - '0') <= 9;
/*=================================ParseFraction==========================
**Action: Starting at the str.Index, which should be a decimal symbol.
// This is the helper function to handle timezone in string in the format like +/-0800
private static bool HandleTimeZone(ref __DTString str, ref DateTimeResult result)
{
- if ((str.Index < str.len - 1))
+ if ((str.Index < str.Length - 1))
{
char nextCh = str.Value[str.Index];
// Skip whitespace, but don't update the index unless we find a time zone marker
int whitespaceCount = 0;
- while (Char.IsWhiteSpace(nextCh) && str.Index + whitespaceCount < str.len - 1)
+ while (Char.IsWhiteSpace(nextCh) && str.Index + whitespaceCount < str.Length - 1)
{
whitespaceCount++;
nextCh = str.Value[str.Index + whitespaceCount];
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;
}
}
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
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;
}
// "11:22:33.1234" or "11:22:33-08".
if (dps == DS.T_NNt)
{
- if ((str.Index < str.len - 1))
+ if ((str.Index < str.Length - 1))
{
char nextCh = str.Value[str.Index];
if (nextCh == '.')
}
if (dps == DS.T_NNt || dps == DS.T_Nt)
{
- if ((str.Index < str.len - 1))
+ if ((str.Index < str.Length - 1))
{
if (false == HandleTimeZone(ref str, ref result))
{
}
else
{
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
LexTraceExit("0030 (TM.AM/TM.PM Happened more than 1x)", dps);
}
break;
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;
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;
}
LexTraceExit("0050 (success)", dps);
return true;
}
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
LexTraceExit("0060", dps);
return false;
}
// 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;
}
}
else
{
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
break;
}
if (dps == DS.T_NNt || dps == DS.T_Nt)
{
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;
}
break;
default:
// Invalid separator after number number.
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
LexTraceExit("0080", dps);
return false;
}
goto default;
default:
// Invalid separator after number number.
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
LexTraceExit("0090", dps);
return false;
}
else
{
// Invalid separator after number number.
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
LexTraceExit("0100", dps);
return false;
}
break;
default:
// Invalid separator after number number.
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
LexTraceExit("0110", dps);
return false;
}
}
else
{
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
LexTraceExit("0120 (DayOfWeek seen more than 1x)", dps);
return false;
}
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;
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;
}
}
else
{
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
LexTraceExit("0140 (MonthToken seen more than 1x)", dps);
return false;
}
}
else
{
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
LexTraceExit("0150 (EraToken seen when result.era already set)", dps);
return false;
}
}
else
{
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
LexTraceExit("0160 (JapaneseEraToken seen when result.era already set)", dps);
return false;
}
}
else
{
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
LexTraceExit("0170 (TEraToken seen when result.era already set)", dps);
return false;
}
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;
}
}
else
{
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
LexTraceExit("0190 (AM/PM timeMark already set)", dps);
return false;
}
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);
}
return true;
}
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
LexTraceExit("0240", dps);
return false;
}
{
bool foundStart = false;
bool foundEnd = false;
- for (int i = 0; i < str.len; i++)
+ for (int i = 0; i < str.Length; i++)
{
ch = str.Value[i];
if (ch == '#')
}
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;
// 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;
}
else if (ch == '\0')
{
- for (int i = str.Index; i < str.len; i++)
+ for (int i = str.Index; i < str.Length; i++)
{
if (str.Value[i] != '\0')
{
}
}
// Move to the end of the string
- str.Index = str.len;
+ str.Index = str.Length;
return true;
}
return false;
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;
}
return true;
}
}
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
return false;
}
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;
}
return true;
}
}
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
return false;
}
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;
}
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;
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;
return true;
}
}
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
return false;
}
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;
}
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;
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;
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;
}
}
}
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
return false;
}
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;
}
return true; // Year + MD
}
}
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
return false;
}
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;
}
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;
}
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;
}
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;
}
result.flags |= ParseFlags.HaveDate;
return true;
}
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
return false;
}
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;
}
//
//
if (raw.timeMark == TM.NotSet)
{
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
return false;
}
result.Hour = raw.GetNumber(0);
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;
}
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");
{
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);
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;
}
}
}
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
return false;
}
//
////////////////////////////////////////////////////////////////////////
- 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)
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))
// 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;
}
}
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;
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))
// 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)
// 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)
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.
return true;
}
- internal static DateTime Parse(String s, DateTimeFormatInfo dtfi, DateTimeStyles styles)
+ 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;
}
}
- internal static DateTime Parse(String s, DateTimeFormatInfo dtfi, DateTimeStyles styles, out TimeSpan offset)
+ 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))
{
}
- internal static bool TryParse(String s, DateTimeFormatInfo dtfi, DateTimeStyles styles, out DateTime result)
+ internal static bool TryParse(ReadOnlySpan<char> s, DateTimeFormatInfo dtfi, DateTimeStyles styles, out DateTime result)
{
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;
return false;
}
- internal static bool TryParse(String s, DateTimeFormatInfo dtfi, DateTimeStyles styles, out DateTime result, out TimeSpan offset)
+ internal static bool TryParse(ReadOnlySpan<char> s, DateTimeFormatInfo dtfi, DateTimeStyles styles, out DateTime result, out TimeSpan offset)
{
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))
{
//
// This is the real method to do the parsing work.
//
- internal static bool TryParse(String s, DateTimeFormatInfo dtfi, DateTimeStyles styles, ref DateTimeResult result)
+ internal static bool TryParse(ReadOnlySpan<char> s, DateTimeFormatInfo dtfi, DateTimeStyles styles, ref DateTimeResult result)
{
- if (s == null)
- {
- result.SetFailure(ParseFailureKind.ArgumentNull, nameof(SR.ArgumentNull_String), null, nameof(s));
- 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 (!ProcessDateTimeSuffix(ref result, ref raw, ref dtok))
{
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
TPTraceExit("0010", dps);
return false;
}
}
else
{
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
TPTraceExit("0030", dps);
return false;
}
{
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)
{
{
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;
if (dps == DS.ERROR)
{
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
TPTraceExit("0040 (invalid state transition)", dps);
return false;
}
{
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;
}
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;
if (!reachTerminalState)
{
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
TPTraceExit("0070 (did not reach terminal state)", dps);
return false;
}
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;
}
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;
}
//
// 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)
{
//
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;
}
result.parsedDate = time;
- if (!DetermineTimeZoneAdjustments(ref result, styles, bTimeOnly))
+ if (!DetermineTimeZoneAdjustments(ref str, ref result, styles, bTimeOnly))
{
TPTraceExit("0120 (DetermineTimeZoneAdjustments)", dps);
return false;
// 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
{
// 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;
}
}
}
// 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)
{
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;
}
}
// 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;
}
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);
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);
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();
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--;
result.flags |= ParseFlags.TimeZoneUsed;
if (!ParseTimeZone(ref str, ref result.timeZoneOffset))
{
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
return false;
}
}
{
if (!VerifyValidPunctuation(ref str))
{
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
return false;
}
str.SkipWhiteSpaces();
{
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;
}
}
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;
}
Debug.Assert(minDigitLen > 0, "minDigitLen > 0");
Debug.Assert(maxDigitLen < 9, "maxDigitLen < 9");
Debug.Assert(minDigitLen <= maxDigitLen, "minDigitLen <= maxDigitLen");
- result = 0;
+ int localResult = 0;
int startingIndex = str.Index;
int tokenLength = 0;
while (tokenLength < maxDigitLen)
str.Index--;
break;
}
- result = result * 10 + str.GetDigit();
+ localResult = localResult * 10 + str.GetDigit();
tokenLength++;
}
+ result = localResult;
if (tokenLength < minDigitLen)
{
str.Index = startingIndex;
result = result * 10 + str.GetDigit();
}
- result = ((double)result / Math.Pow(10, digitLen));
+ result /= TimeSpanParse.Pow10(digitLen);
return (digitLen == maxDigitLen);
}
// 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;
}
}
- // assume the offset is Local
+ // assume the offset is Local
return DateTime.Now;
}
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;
}
}
// 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,
}
if (!parseResult)
{
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
return (false);
}
if (!CheckNewValue(ref result.Year, tempYear, ch, ref result))
if (!parseInfo.fCustomNumberParser ||
!parseInfo.parseNumberDelegate(ref str, tokenLen, out tempMonth))
{
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
return (false);
}
}
{
if (!MatchAbbreviatedMonthName(ref str, dtfi, ref tempMonth))
{
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
return (false);
}
}
{
if (!MatchMonthName(ref str, dtfi, ref tempMonth))
{
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
return (false);
}
}
if (!parseInfo.fCustomNumberParser ||
!parseInfo.parseNumberDelegate(ref str, tokenLen, out tempDay))
{
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
return (false);
}
}
// "ddd"
if (!MatchAbbreviatedDayName(ref str, dtfi, ref tempDayOfWeek))
{
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
return (false);
}
}
// "dddd*"
if (!MatchDayName(ref str, dtfi, ref tempDayOfWeek))
{
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
return (false);
}
}
// 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;
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))
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))
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))
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))
{
if (ch == 'f')
{
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
return (false);
}
}
}
else
{
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
return (false);
}
break;
{
if (!MatchAbbreviatedTimeMark(ref str, dtfi, ref tempTimeMark))
{
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
return (false);
}
}
{
if (!MatchTimeMark(ref str, dtfi, ref tempTimeMark))
{
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
return (false);
}
}
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)
str.Index++;
if (!GetTimeZoneName(ref str))
{
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
return false;
}
str.Index--;
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)
!str.Match(dtfi.TimeSeparator))
{
// A time separator is expected.
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
return false;
}
break;
!str.Match(dtfi.DateSeparator))
{
// A date separator is expected.
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
return false;
}
break;
case '\"':
case '\'':
- StringBuilder enquotedString = new StringBuilder();
+ StringBuilder enquotedString = StringBuilderCache.Acquire();
// Use ParseQuoteString so that we can handle escape characters within the quoted string.
if (!TryParseQuoteString(format.Value, format.Index, enquotedString, out tokenLen))
{
result.SetFailure(ParseFailureKind.FormatWithParameter, nameof(SR.Format_BadQuote), ch);
+ StringBuilderCache.Release(enquotedString);
return (false);
}
format.Index += tokenLen - 1;
// Some cultures uses space in the quoted string. E.g. Spanish has long date format as:
// "dddd, dd' de 'MMMM' de 'yyyy". When inner spaces flag is set, we should skip whitespaces if there is space
// in the quoted string.
- String quotedStr = enquotedString.ToString();
+ String quotedStr = StringBuilderCache.GetStringAndRelease(enquotedString);
for (int i = 0; i < quotedStr.Length; i++)
{
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)
// 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;
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;
break;
}
}
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
return false;
}
break;
}
}
}
- result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
+ result.SetBadDateTimeFailure();
return false;
}
// Found a macth.
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;
}
}
// The pos should point to a quote character. This method will
// get the string enclosed by the quote character.
//
- internal static bool TryParseQuoteString(String format, int pos, StringBuilder result, out int returnValue)
+ internal static bool TryParseQuoteString(ReadOnlySpan<char> format, int pos, StringBuilder result, out int returnValue)
{
//
// NOTE : pos will be the index of the quote character in the 'format' string.
==============================================================================*/
private static bool DoStrictParse(
- String s,
- String formatParam,
+ ReadOnlySpan<char> s,
+ ReadOnlySpan<char> formatParam,
DateTimeStyles styles,
DateTimeFormatInfo dtfi,
ref DateTimeResult result)
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);
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;
}
// 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;
}
}
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)
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;
}
}
{
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)
//
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;
}
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;
return buffer.ToString();
}
// return a string in the form: "Sun"
- internal static string Hex(string str)
+ private static string Hex(string str) => Hex((ReadOnlySpan<char>)str);
+ private static string Hex(ReadOnlySpan<char> str)
{
StringBuilder buffer = new StringBuilder();
buffer.Append("\"");
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);
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
}
// It has a Index property which tracks
// the current parsing pointer of the string.
//
- internal
- struct __DTString
+ internal ref struct __DTString
{
//
// Value propery: stores the real string to be parsed.
//
- internal String Value;
+ internal ReadOnlySpan<char> Value;
//
// Index property: points to the character that we are currently parsing.
internal int Index;
// The length of Value string.
- internal int len;
+ internal int Length => Value.Length;
// The current chracter to be looked at.
internal char m_current;
// In some cultures, such as mn-MN, it uses "\x0031\x00a0\x0434\x04af\x0433\x044d\x044d\x0440\x00a0\x0441\x0430\x0440" in month names.
private bool m_checkDigitToken;
- internal __DTString(String str, DateTimeFormatInfo dtfi, bool checkDigitToken) : this(str, dtfi)
+ internal __DTString(ReadOnlySpan<char> str, DateTimeFormatInfo dtfi, bool checkDigitToken) : this(str, dtfi)
{
m_checkDigitToken = checkDigitToken;
}
- internal __DTString(String str, DateTimeFormatInfo dtfi)
+ internal __DTString(ReadOnlySpan<char> str, DateTimeFormatInfo dtfi)
{
Index = -1;
Value = str;
- len = Value.Length;
m_current = '\0';
if (dtfi != null)
internal bool GetNext()
{
Index++;
- if (Index < len)
+ if (Index < Length)
{
m_current = Value[Index];
return (true);
internal bool AtEnd()
{
- return Index < len ? false : true;
+ return Index < Length ? false : true;
}
internal bool Advance(int count)
{
- Debug.Assert(Index + count <= len, "__DTString::Advance: Index + count <= len");
+ Debug.Assert(Index + count <= Length, "__DTString::Advance: Index + count <= len");
Index += count;
- if (Index < len)
+ if (Index < Length)
{
m_current = Value[Index];
return (true);
internal void GetRegularToken(out TokenType tokenType, out int tokenValue, DateTimeFormatInfo dtfi)
{
tokenValue = 0;
- if (Index >= len)
+ if (Index >= Length)
{
tokenType = TokenType.EndOfString;
return;
//
// Collect other digits.
//
- while (++Index < len)
+ while (++Index < Length)
{
m_current = Value[Index];
value = m_current - '0';
else if (Char.IsWhiteSpace(m_current))
{
// Just skip to the next character.
- while (++Index < len)
+ while (++Index < Length)
{
m_current = Value[Index];
if (!(Char.IsWhiteSpace(m_current)))
return (tokenType);
}
- internal bool MatchSpecifiedWord(String target)
- {
- return MatchSpecifiedWord(target, target.Length + Index);
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal bool MatchSpecifiedWord(String target) =>
+ Index + target.Length <= Length &&
+ m_info.Compare(Value.Slice(Index, target.Length), target, CompareOptions.IgnoreCase) == 0;
- internal bool MatchSpecifiedWord(String target, int endIndex)
- {
- int count = endIndex - Index;
-
- if (count != target.Length)
- {
- return false;
- }
-
- if (Index + count > len)
- {
- return false;
- }
-
- return (m_info.Compare(Value, Index, count, target, 0, count, CompareOptions.IgnoreCase) == 0);
- }
-
- private static Char[] WhiteSpaceChecks = new Char[] { ' ', '\u00A0' };
+ private static readonly Char[] WhiteSpaceChecks = new Char[] { ' ', '\u00A0' };
internal bool MatchSpecifiedWords(String target, bool checkWordBoundary, ref int matchLength)
{
int valueRemaining = Value.Length - Index;
matchLength = target.Length;
- if (matchLength > valueRemaining || m_info.Compare(Value, Index, matchLength, target, 0, matchLength, CompareOptions.IgnoreCase) != 0)
+ if (matchLength > valueRemaining || m_info.Compare(Value.Slice(Index, matchLength), target, CompareOptions.IgnoreCase) != 0)
{
// Check word by word
int targetPosition = 0; // Where we are in the target string
{
return false;
}
- if (m_info.Compare(Value, thisPosition, segmentLength, target, targetPosition, segmentLength, CompareOptions.IgnoreCase) != 0)
+ if (m_info.CompareOptionIgnoreCase(Value.Slice(thisPosition, segmentLength), target.AsSpan(targetPosition, segmentLength)) != 0)
{
return false;
}
{
return false;
}
- if (m_info.Compare(Value, thisPosition, segmentLength, target, targetPosition, segmentLength, CompareOptions.IgnoreCase) != 0)
+ if (m_info.CompareOptionIgnoreCase(Value.Slice(thisPosition, segmentLength), target.AsSpan(targetPosition, segmentLength)) != 0)
{
return false;
}
//
internal bool Match(String str)
{
- if (++Index >= len)
+ if (++Index >= Length)
{
return (false);
}
return false;
}
- if (m_info.Compare(Value, Index, str.Length, str, 0, str.Length, CompareOptions.Ordinal) == 0)
+ if (m_info.Compare(Value.Slice(Index, str.Length), str, CompareOptions.Ordinal) == 0)
{
// Update the Index to the end of the matching string.
// So the following GetNext()/Match() opeartion will get
internal bool Match(char ch)
{
- if (++Index >= len)
+ if (++Index >= Length)
{
return (false);
}
{
char repeatChar = Value[Index];
int pos = Index + 1;
- while ((pos < len) && (Value[pos] == repeatChar))
+ while ((pos < Length) && (Value[pos] == repeatChar))
{
pos++;
}
}
// Return false when end of string is encountered or a non-digit character is found.
- internal bool GetNextDigit()
- {
- if (++Index >= len)
- {
- return (false);
- }
- return (DateTimeParse.IsDigit(Value[Index]));
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal bool GetNextDigit() =>
+ ++Index < Length &&
+ DateTimeParse.IsDigit(Value[Index]);
//
// Get the current character.
//
internal char GetChar()
{
- Debug.Assert(Index >= 0 && Index < len, "Index >= 0 && Index < len");
+ Debug.Assert(Index >= 0 && Index < Length, "Index >= 0 && Index < len");
return (Value[Index]);
}
//
internal int GetDigit()
{
- Debug.Assert(Index >= 0 && Index < len, "Index >= 0 && Index < len");
+ Debug.Assert(Index >= 0 && Index < Length, "Index >= 0 && Index < len");
Debug.Assert(DateTimeParse.IsDigit(Value[Index]), "IsDigit(Value[Index])");
return (Value[Index] - '0');
}
{
// Look ahead to see if the next character
// is a whitespace.
- while (Index + 1 < len)
+ while (Index + 1 < Length)
{
char ch = Value[Index + 1];
if (!Char.IsWhiteSpace(ch))
//
internal bool SkipWhiteSpaceCurrent()
{
- if (Index >= len)
+ if (Index >= Length)
{
return (false);
}
return (true);
}
- while (++Index < len)
+ while (++Index < Length)
{
m_current = Value[Index];
if (!Char.IsWhiteSpace(m_current))
internal void TrimTail()
{
- int i = len - 1;
+ int i = Length - 1;
while (i >= 0 && Char.IsWhiteSpace(Value[i]))
{
i--;
}
- Value = Value.Substring(0, i + 1);
- len = Value.Length;
+ Value = Value.Slice(0, i + 1);
}
// Trim the trailing spaces within a quoted string.
// Call this after TrimTail() is done.
internal void RemoveTrailingInQuoteSpaces()
{
- int i = len - 1;
+ int i = Length - 1;
if (i <= 1)
{
return;
// 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);
- len = Value.Length;
+ Span<char> result = new char[i + 1];
+ result[i] = ch;
+ Value.Slice(0, i).CopyTo(result);
+ Value = result;
}
}
}
// Call this after the leading spaces before quoted string are trimmed.
internal void RemoveLeadingInQuoteSpaces()
{
- if (len <= 2)
+ if (Length <= 2)
{
return;
}
// Check if the last character is a quote.
if (ch == '\'' || ch == '\"')
{
- while ((i + 1) < len && Char.IsWhiteSpace(Value[i + 1]))
+ while ((i + 1) < Length && char.IsWhiteSpace(Value[i + 1]))
{
i++;
}
if (i != 0)
{
- Value = Value.Remove(1, i);
- len = Value.Length;
+ Span<char> result = new char[Value.Length - i];
+ result[0] = ch;
+ Value.Slice(i + 1).CopyTo(result.Slice(1));
+ Value = result;
}
}
}
DTSubString sub = new DTSubString();
sub.index = Index;
sub.s = Value;
- while (Index + sub.length < len)
+ while (Index + sub.length < Length)
{
DTSubStringType currentType;
Char ch = Value[Index + sub.length];
internal void ConsumeSubString(DTSubString sub)
{
Debug.Assert(sub.index == Index, "sub.index == Index");
- Debug.Assert(sub.index + sub.length <= len, "sub.index + sub.length <= len");
+ Debug.Assert(sub.index + sub.length <= Length, "sub.index + sub.length <= len");
Index = sub.index + sub.length;
- if (Index < len)
+ if (Index < Length)
{
m_current = Value[Index];
}
Other = 4,
}
- internal struct DTSubString
+ internal ref struct DTSubString
{
- internal String s;
+ internal ReadOnlySpan<char> s;
internal Int32 index;
internal Int32 length;
internal DTSubStringType type;
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]
// used to construct a DateTime instance.
//
internal
- struct DateTimeResult
+ ref struct DateTimeResult
{
internal int Year;
internal int Month;
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;
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;