internal static bool TryParse(String s, DateTimeFormatInfo dtfi, DateTimeStyles styles, ref DateTimeResult result) {
if (s == null) {
result.SetFailure(ParseFailureKind.ArgumentNull, "ArgumentNull_String", null, "s");
return false;
}
if (s.Length == 0) {
result.SetFailure(ParseFailureKind.Format, "Format_BadDateTime", null);
return false;
}
BCLDebug.Assert(dtfi != null, "dtfi == null");
DateTime time;
//
// First try the predefined format.
//
DS dps = DS.BEGIN; // Date Parsing State.
bool reachTerminalState = false;
DateTimeToken dtok = new DateTimeToken(); // The buffer to store the parsing token.
dtok.suffix = TokenType.SEP_Unk;
DateTimeRawInfo raw = new DateTimeRawInfo(); // The buffer to store temporary parsing information.
unsafe {
Int32 * numberPointer = stackalloc Int32[3];
raw.Init(numberPointer);
}
result.calendar = dtfi.Calendar;
result.era = Calendar.CurrentEra;
//
// The string to be parsed. Use a __DTString wrapper so that we can trace the index which
// indicates the begining of next token.
//
__DTString str = new __DTString(s, dtfi);
str.GetNext();
//
// The following loop will break out when we reach the end of the str.
//
do {
//
// Call the lexer to get the next token.
//
// If we find a era in Lex(), the era value will be in raw.era.
if (!Lex(dps, ref str, ref dtok, ref raw, ref result, ref dtfi)) {
return false;
}
//
// If the token is not unknown, process it.
// Otherwise, just discard it.
//
if (dtok.dtt != DTT.Unk)
{
//
// Check if we got any CJK Date/Time suffix.
// Since the Date/Time suffix tells us the number belongs to year/month/day/hour/minute/second,
// store the number in the appropriate field in the result.
//
if (dtok.suffix != TokenType.SEP_Unk)
{
if (!ProcessDateTimeSuffix(ref result, ref raw, ref dtok)) {
result.SetFailure(ParseFailureKind.Format, "Format_BadDateTime", null);
return false;
}
dtok.suffix = TokenType.SEP_Unk; // Reset suffix to SEP_Unk;
}
if (dtok.dtt == DTT.NumLocalTimeMark) {
if (dps == DS.D_YNd || dps == DS.D_YN) {
return (ParseISO8601(ref raw, ref str, styles, ref result));
}
else {
result.SetFailure(ParseFailureKind.Format, "Format_BadDateTime", null);
return false;
}
}
//
// Advance to the next state, and continue
//
dps = dateParsingStates[(int)dps][(int)dtok.dtt];
if (dps == DS.ERROR)
{
result.SetFailure(ParseFailureKind.Format, "Format_BadDateTime", null);
return false;
}
else if (dps > DS.ERROR)
{
if ((dtfi.FormatFlags & DateTimeFormatFlags.UseHebrewRule) != 0) {
if (!ProcessHebrewTerminalState(dps, ref result, ref raw, dtfi)) {
return false;
}
} else {
if (!ProcessTerminaltState(dps, ref result, ref raw, dtfi)) {
return false;
}
}
reachTerminalState = true;
//
// If we have reached a terminal state, start over from DS.BEGIN again.
// For example, when we parsed "1999-12-23 13:30", we will reach a terminal state at "1999-12-23",
// and we start over so we can continue to parse "12:30".
//
dps = DS.BEGIN;
}
}
} while (dtok.dtt != DTT.End && dtok.dtt != DTT.NumEnd && dtok.dtt != DTT.MonthEnd);
if (!reachTerminalState) {
result.SetFailure(ParseFailureKind.Format, "Format_BadDateTime", null);
return false;
}
AdjustTimeMark(dtfi, ref raw);
if (!AdjustHour(ref result.Hour, raw.timeMark)) {
result.SetFailure(ParseFailureKind.Format, "Format_BadDateTime", null);
return false;
}
// Check if the parased string only contains hour/minute/second values.
bool bTimeOnly = (result.Year == -1 && result.Month == -1 && result.Day == -1);
//
// Check if any year/month/day is missing in the parsing string.
// If yes, get the default value from today's date.
//
CheckDefaultDateTime(ref result, ref result.calendar, styles);
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, "Format_BadDateTimeCalendar", null);
return false;
}
if (raw.fraction > 0) {
time = time.AddTicks((long)Math.Round(raw.fraction * Calendar.TicksPerSecond));
}
//
// 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.
//
if (raw.dayOfWeek != -1) {
//
// Check if day of week is correct.
//
if (raw.dayOfWeek != (int)result.calendar.GetDayOfWeek(time)) {
result.SetFailure(ParseFailureKind.Format, "Format_BadDayOfWeek", null);
return false;
}
}
result.parsedDate = time;
if (!DetermineTimeZoneAdjustments(ref result, styles, bTimeOnly)) {
return false;
}
return true;
}